第二篇-Vue3 项目中集成 element-plus

基于上次使用 cli 搭建的 vue3 的项目来添加 element-plus cli搭建vue3项目

安装element-plus

在项目所在目录打开命令行工具,执行以下命令安装

1
2
3
npm install element-plus --save
#or
yarn add element-plus

我这里安装的最新版本是 1.1.0-beta.9

升级sass、sass-loader

为什么要升级 sasssass-loader?

使用脚手架安装的 sass 的版本是 1.26.5sass-loader 的版本是 8.0.2,而 element-plus@1.1.0-beta.9 版本的源码中使用的 sass 的版本是 1.39.0, sass-loader 的版本是 10.1.1

那我们就需要安装一下这两个版本,命令行执行以下命令

1
2
3
npm install sass@1.39.0 sass-loader@10.1.1 --save-dev
#or
yarn add sass@1.39.0 sass-loader@10.1.1 --dev

使用按需引入

为什么要使用按需引入?

element-plus 的组件比较多,而我们的项目开发中并不一定会用到所有的组件,如果我们直接引入所有的组件,那么项目打包之后的文件体积较大,会导致浏览器的加载时间长,从而导致一些白屏时间长等的问题。

使用按需引入之后,在项目打包的时候,只会把我们引入的组件进行打包,其他我们没有引入使用的组件,不会打包我们的项目中,减少我们项目的体积,加快浏览器的加载效率。

配置按需引入

  1. 首先需要下载一个 babel 的插件 babel-plugin-import,命令行执行
1
2
3
npm install babel-plugin-import --save-dev
#or
yarn add babel-plugin-import --dev
  1. 找到项目根目录下的 babel.config.js 文件

添加 babel.config.js 配置,将文件内容修改为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
module.exports = {
presets: ["@vue/cli-plugin-babel/preset"],
plugins: [
[
"import",
{
libraryName: "element-plus",
// 引入组件
customName: (name) => {
name = name.slice(3);
return `element-plus/lib/components/${name}`;
},
// 不引入样式,因为之后会做主题定制,所以需要引入所有样式的scss文件
},
],
],
};

测试按需引入是否正确

src/main.ts 中,引入 element-plus 的样式文件

1
import "element-plus/dist/index.css";

src/App.vue 中,添加 script 代码

1
2
3
<script setup>
import { ElButton } from "element-plus";
</script>

template 中添加一个 el-button 组件

1
<el-button type="primary">测试按需引入</el-button>

App.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<template>
<div id="nav">
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link>
</div>
<el-button type="primary">测试按需引入</el-button>
<router-view />
</template>

<script setup>
import { ElButton } from "element-plus";
</script>
<style lang="scss">
// ... 省略css代码
</style>

运行项目,浏览器访问

image-20210906220500007

el-button 组件就很好的显示在了页面上

把按需引入提取到单独的目录

为什么要提取到单独的目录来,有一个好处就是只需要在这里引入一次,并注册成全局的组件之后,就不需要在每个需要用到 element-plus 的组件里面再次引入了。

我一般会在 src 目录下,创建一个 theme 文件夹,专门做按需加载和主题定制

创建一个 theme 文件夹,并在目录下创建一个 index.ts 的文件

将刚才引入 el-button 的代码放到这个文件中,并将组件注册为全局的组件,在这里文件里,我们将导出一个函数,这个函数会作为 Vue 的一个插件,在 main.ts 中通过 app.use() 的方式注册到全局

index.ts

1
2
3
4
5
6
import { App } from "vue";
import { ElButton } from "element-plus";

export default (app: App): void => {
app.use(ElButton);
};

main.ts

1
2
3
4
5
6
7
8
9
10
11
12
import { createApp } from "vue";
import App from "./App.vue";
import router from "./router";
import store from "./store";
import Element from "./theme";

const app = createApp(App);
app.use(store);
app.use(router);
app.use(Element);
app.mount("#app");

测试一下我们的提取的按需引入是否正确

删掉刚才在 App.vue 中添加的 script 标签

1
2
3
4
5
6
7
8
9
10
11
<template>
<div id="nav">
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link>
</div>
<el-button type="primary">测试按需引入</el-button>
<router-view />
</template>

<style lang="scss">
</style>

刷新浏览器,发现 el-button 的组件渲染的和之前一样,没有问题

image-20210906221751777

配置 element-plus 的全局属性

element-plus 还为我们提供了两个可以全局配置的属性, sizezIndex,还是在我们的 theme/index.ts 文件中配置,修改导出的函数,给 app.config.globalProperties.$ELEMENT 属性赋值

1
2
3
4
export default (app: App): void => {
app.config.globalProperties.$ELEMENT = { size: "small" };
app.use(ElButton);
};

然后打开浏览器,可以发现 el-button 的按钮,比刚才小了很多了

image-20210906222202680

配置 i18n

ElementPlus 组件内部默认使用英语,如果我们希望我们的项目中默认使用中文,就需要对 element-plus 配置 i18n,先来看一个默认英文的例子

theme/index.ts 文件中引入 ElCalendar 组件

1
2
3
4
5
6
7
8
import { App } from "vue";
import { ElButton, ElCalendar } from "element-plus";

export default (app: App): void => {
app.config.globalProperties.$ELEMENT = { size: "small" };
app.use(ElButton);
app.use(ElCalendar);
};

src/App.vue 中使用 ElCalendar 组件

1
2
3
4
5
6
7
8
9
<template>
<div id="nav">
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link>
</div>
<el-button type="primary">测试按需引入</el-button>
<el-calendar />
<router-view />
</template>

打开浏览器会发现日历的头部和按钮都是显示的英文

image-20210906222945434

接下来我们配置 i18n,还是在我们的 theme/index.ts 文件中,引入 ElConfigProvider 组件,并在 src/App.vue 中使用

theme/index.ts

1
2
3
4
5
6
7
8
9
import { App } from "vue";
import { ElButton, ElCalendar, ElConfigProvider } from "element-plus";

export default (app: App): void => {
app.config.globalProperties.$ELEMENT = { size: "small" };
app.use(ElButton);
app.use(ElCalendar);
app.use(ElConfigProvider);
};

App.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<template>
<el-config-provider :locale="zhCn">
<div id="nav">
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link>
</div>
<el-button type="primary">测试按需引入</el-button>
<el-calendar />
<router-view />
</el-config-provider>
</template>

<script setup lang="ts">
import zhCn from "element-plus/lib/locale/lang/zh-cn";
</script>
<style lang="scss">
// ...
</style>

再次打开浏览器,就可以看到日历的按钮已经变成中文了,但是日历的头部还是英文的展示,这是因为 element-plus 的中的时间和日期相关的组件,都使用了 dayjs 格式化,所以我们这里想把日历的头部 改成中文还需要引入一下 dayjs 的中文包

theme/index.ts 中添加引入

1
import "dayjs/locale/zh-cn";

配置主题定制

element-plus 给我们提供了一套默认的主题,同时给我们提供了四种方法,可以进行不同程度的样式自定义。这里只说其中的一种,其他的方式,感兴趣的可以前往官网查阅

通过修改scss变量的方式,替换主题的样式

在我们的 src/theme 目录下新建一个 element-variables.scss 的文件,之后我们需要定制的 element-plus 主题的 scss 变量都会在这个文件重写。

不要使用官网推荐的 element-theme 工具,已经很久没有人维护了,在最新版本的node环境下使用会报错。

在我们项目的根目录下找到 node_modules/element-plus/theme-chalk/src/common/var.scss 这个文件,这里面所有后面带有 !default 的就是我们可以修改的所有的 scss 的变量了

image-20210907132210264

比如说我们想要修改一下 primary 的样式,我们查找 var.scss 文件发现,关于 primary 颜色的定义就在第 21 行,$--colors 的初始值就是带有 !default 的, 我们在 element-variables.scss 文件中对 $--colors 重新赋值就可以修改 primary 的颜色

src/theme/element-variables.scss

1
2
3
4
5
$--colors: (
'primary': (
'base': #000,
),
);

注意:要通过修改scss变量的方式自定义主题,必须重新设置 font 文件路径

引入 element-plus/packages/theme-chalk/src/index.scss 之后,就可以修改 scss 的变量了

所以我们在 src/theme 文件夹下在新建一个 index.scss 文件,用来引入自定义的主题并处理 font 路径和 element-plus 的 scss 文件

src/theme/index.scss

1
2
3
@import "./element-variables.scss";
$--font-path: "~element-plus/theme-chalk/fonts";
@import "~element-plus/packages/theme-chalk/src/index";

src/theme/index.ts 文件中引入这个文件 import "./index.scss";

src/theme/index.ts

1
2
3
4
5
6
7
8
9
10
11
import { App } from "vue";
import "dayjs/locale/zh-cn";
import { ElButton, ElCalendar, ElConfigProvider } from "element-plus";
import "./index.scss";

export default (app: App): void => {
app.config.globalProperties.$ELEMENT = { size: "small" };
app.use(ElButton);
app.use(ElCalendar);
app.use(ElConfigProvider);
};

删除 src.main.ts 中引入样式的代码 import "element-plus/dist/index.css";

刷新浏览器就可以看到我们修改的主题的样式了

image-20210907174921543

配置 scss 全局变量文件

在我们的项目开发过程中,不可能只使用 element-plus 的组件和样式,所以我们会需要维护一套我们自己的 scss ,为了样式的统一和以后的好维护,我们应该使用和 element-plus 类似的这种全局变量的方式,定义我们的统一的颜色、边框等等

src/assets 目录下新建一个 scss 文件夹,在其中新建以下文件

  • var.scss 定义全局的变量
  • mixin.scss 定义全局的混入
  • fun.scss 定义全局的函数
  • common.scss 全局的样式,这个文件会定义一些具体的选择器的样式,上面的其他文件中定义都是不会被直接编译出 css 代码的

在 sass-loader中配置成全局scss文件

在项目根目录下创建 vue.config.js 文件,并添加 css 配置

vue.config.js

1
module.exports = {  css: {    loaderOptions: {      scss: {        additionalData: `          @import "~@/assets/scss/var.scss";          @import "~@/assets/scss/mixin.scss";          @import "~@/assets/scss/fun.scss";        `,      },    },  },};

验证一下全局的 scss 文件是否配置成功

src/assets/scss/var.sass 中添加变量 $primary-color: red;,把刚才修改的 src/theme/element-variables 文件中的 primary 的颜色设置成 $primary-color

src/assets/scss/var.scss

1
$primary-color: red;

src/theme/element-variables.scss

1
$--colors: (  'primary': (    'base': $primary-color,  ),);

src/assets/scss/fun.scss 文件中添加一个 toRem 函数,在 src/App.vue 中调用这个函数

src/App.vue 中添加一个标签 <div class="bg-red"></div>,在 style 标签里给 div 定义一个样式,使用 $primary-color 变量和 toRem 函数

src/assets/scss/fun.scss

1
@function toRem($px) {  @return $px / 75px * 1rem;}

实际开发中,如果有需要 px 转 rem 的操作,建议可以使用 postcss 的插件 pxtorem ,可以不用每次都要都要写 toRem(),这里只是用来做一下演示

src/App.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<template>
<el-config-provider :locale="zhCn">
<!-- 省略其余代码 -->
<div class="bg-red"></div>
<router-view />
</el-config-provider>
</template>

<script>
// ... 省略js代码
</script>
<style lang="scss">
.bg-red {
width: toRem(200px);
height: toRem(200px);
background: $primary-color;
}
</style>

在项目编译的时候给出了以下警告,使用 / 表示除法已经被废弃,应该使用 math.div 方法

image-20210908102741714

修改一下 src/assets/scss/fun.scss 文件

1
2
3
4
@use "sass:math";
@function toRem($px) {
@return math.div($px, 75px) * 1rem;
}

打开浏览器可以看到红色的按钮,和 div 的样式,宽高已经是 rem 的单位,并且背景也红色

image-20210907185538057

最后,在 src/main.ts 中引入 common.scss 文件

1
import "@/assets/scss/common.scss";

添加 reset.scss 文件

在项目开发中,为了减少浏览器在默认行高、页边距和标题字体大小等方面的不一致,需要重置样式表

src/assets/scss 下新建 reset.scss 文件

src/assets/scss/reset.scss

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed,
figure, figcaption, footer, header, hgroup,
menu, nav, output, ruby, section, summary,
time, mark, audio, video {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
font: inherit;
vertical-align: baseline;
}
/* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure,
footer, header, hgroup, menu, nav, section {
display: block;
}
body {
line-height: 1;
}
ol, ul {
list-style: none;
}
blockquote, q {
quotes: none;
}
blockquote:before, blockquote:after,
q:before, q:after {
content: '';
content: none;
}
table {
border-collapse: collapse;
border-spacing: 0;
}

src/main.ts 中引入

1
import "@/assets/scss/reset.scss";

### 完结

项目已经上传到 github 和 gitee

GitHub: https://github.com/wukang0718/cli-create-project

Gitee: https://gitee.com/wu_kang0718/cli-create-project

下一篇:配置运行环境