更新于:2021.11.16
关于 element-plus 自定义主题部分, 最新版的 element-plus 1.1.0-beta.1x 官网文档 ➡️ https://element-plus.gitee.io/zh-CN/guide/theming.html 又又又修改了!
不过这回貌似更简单了,按照以下步骤操作即可。
- 创建一个新的样式文件,例如
styles/element/index.scss
,直接覆盖 Element Plus 样式变量:
// styles/element/index.scss
@forward "element-plus/theme-chalk/src/common/var.scss" with (
$colors: (
'primary': (
'base': #4FC08D,
),
'success': (
'base': #8BC34A,
),
'warning': (
'base': #FFE787,
),
'danger': (
'base': #7C77B9,
),
'error': (
'base': #E65D6E,
),
'info': (
'base': #606266,
),
),
$text-color: (
'primary': #3FB984,
'regular': #606266,
'secondary': #909399
)
);
如果是完整导入 element-plus,则在入口 main.js/main.ts
:
import Vue from 'vue'
import './styles/element/index.scss'
import ElementPlus from 'element-plus'
import App from './App.vue'
const app = createApp(App)
app.use(ElementPlus)
- 但我们需要在按需导入时自定义主题,并且使用 vite。就可以安装用于按需导入 element-plus 样式的 unplugin-element-plus 插件并进行配置。
vite.config.js
:
// vite.config.ts
import path from 'path'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import vueJsx from '@vitejs/plugin-vue-jsx'
// 自动按需导入 element-plus 样式
import ElementPlus from 'unplugin-element-plus/vite'
export default defineConfig({
resolve: {
alias: {
'@': path.resolve(__dirname, 'src'),
},
},
css: {
preprocessorOptions: {
scss: {
additionalData: `@use "@/styles/element/index.scss" as *;`,
},
},
},
plugins: [
vue(),
ElementPlus({
useSource: true,
}),
],
})
可选配置 useSource: boolean
,默认是 false。
// useSource: false
import { ElButton } from 'element-plus'
↓ ↓ ↓ ↓ ↓ ↓
import { ElButton } from 'element-plus'
import 'element-plus/es/components/button/style/css'
// useSource: true
import { ElButton } from 'element-plus'
↓ ↓ ↓ ↓ ↓ ↓
import { ElButton } from 'element-plus'
import 'element-plus/es/components/button/style/index'。
- 接下来也不需要在使用时手动导入组件,而是配置一个自动导入插件 unplugin-vue-components :
更新于:2021.09.23
element-plus 的官方文档更新了,组件的按需引入可以用 unplugin-vue-components 十分便捷地实现,步骤如下:
- 安装
npm install unplugin-vue-components -D
- 配置文件
vite.config.js
// vite.config.ts/vite.config.js
import { defineConfig } from 'vite'
// vue 按需自动导入组件插件,直接使用即可,公共组件无需再手动 import
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers' // ElementPlus 组件专用的内置解析器
import ElementPlus from 'unplugin-element-plus/vite' // 按需导入 element-plus 样式插件
export default defineConfig({
plugins: [
// ...
Components({
resolvers: [ElementPlusResolver()], // 启用 ElementPlus 专用的 UI 组件解析器
}),
ElementPlus({ useSource: true }), // import 组件后会自动引入组件对应的样式
],
css: {
preprocessorOptions: {
scss: {
// 自定义 element 主题样式
additionalData: `@use "@styles/element/index.scss" as *;`,
},
},
},
})
这样不仅 element-plus 组件,所有src/components
下的公用自定义组件都不需要再做诸如以下这类导入和配置,而是直接在template
中使用即可。
import DesignForm from '@/components/DesignForm.vue'
export default defineComponent({
name: 'DesignIndex',
components: { DesignForm },
...
}
以下是这个插件的默认配置,你可以在vite.config
的插件配置中根据需要自定义
Components({
// 用于查找自动处理的组件目录的相对路径
dirs: ['src/components'],
// 组件的有效文件扩展名
extensions: ['vue'],
// 是否查找子目录
deep: true,
// resolvers for custom components
resolvers: [],
// example of importing Vant,不是默认值
/* resolvers: [
(name) => {
// where `name` is always CapitalCase
if (name.startsWith('Van'))
return { importName: name.slice(3), path: 'vant' }
},
],*/
// 是否生成 `components.d.ts` 全局声明,
// also accepts a path for custom filename
dts: false,
// 不允许子目录作为组件的命名空间前缀
directoryAsNamespace: false,
// 忽略的命名空间前缀的子目录路径,当 `directoryAsNamespace: true` 时才起作用
globalNamespaces: [],
// 是否自动导入指令
// 默认: `true` for Vue 3, `false` for Vue 2
// Vue2 需要 Babel 来进行转换,出于性能考虑,默认禁用。
// To install Babel, run: `npm install -D @babel/parser @babel/traverse`
directives: true,
// 转换目标的过滤器
include: [/\.vue$/, /\.vue\?vue/],
exclude: [/[\\/]node_modules[\\/]/, /[\\/]\.git[\\/]/, /[\\/]\.nuxt[\\/]/],
})
有没有很省事!但是!当你需要用到自定义主题的时候,这个路子就不好使了。我们还是要像之前那样手动导入(然后全局注册)。 可以放心大胆滴使用~
跟着往下看:
以下(有部分)更新于2021.08.27
今天把 ElementPlus 更新到了最新,然后一跑项目马上就报错了。特记录下1.1.0
版后使用的区别:
package.json
:
{
"dependencies": {
"element-plus": "^1.1.0-beta.9",
"vue": "^3.2.6",
"vue-router": "^4.0.11",
"vuex": "^4.0.2"
},
"devDependencies": {
"@vitejs/plugin-vue": "^1.6.0",
"@vitejs/plugin-vue-jsx": "^1.1.7",
"@vue/compiler-sfc": "^3.0.5",
"sass": "^1.38.1",
"vite": "^2.5.1",
"unplugin-element-plus": "0.1.0",
}
}
用 unplugin-element-plus 插件来实现按需加载样式,别忘了先安装npm i unplugin-element-plus -D
。
但是官方是强烈建议全局引入样式,没必要为此特地用插件增加负担。此外像这样配置按需引入样式也无法使自定义主题生效。so 只是贴在这里记录方法。
按需引入 element-plus 后使用消息组件
Message
和MessageBox
,就需要这样调用:
ElMessage.error('xxx')
ElMessageBox.confirm()
至于
v-loading
指令按需后也不好使了,我封装了个组合函数useLoading
,参考下:
// src/composables/useLoading.js
import { ref, watch, nextTick } from 'vue'
import { ElLoading } from 'element-plus'
/**
@target:Loading 动画需要覆盖的 DOM 对象(ref 对象)
@isLoading:表示数据是否正在加载的 ref 对象
**/
export default function useLoading(target, isLoading) {
const loadingInstance = ref(null)
watch(
[isLoading, target],
vals => {
if (vals[0] && vals[1]) {
nextTick(() => {
loadingInstance.value = ElLoading.service({
target: vals[1].$el, // 需要获取DOM 节点
fullscreen: false,
text: ' 数据加载中',
})
})
} else {
nextTick(() => {
if (loadingInstance.value) loadingInstance.value.close()
})
}
},
{ immediate: true }
)
}
使用简单示例:
:下面的部分都不用看了!!!
正式内容开始:
src/main.js
:
// import 'element-plus/dist/index.css' // 官方建议全局引入样式
import { createApp } from 'vue'
import App from './App.vue'
// 把按需引入 ElementPlus 组件 的代码单独拎到一个 js
import installElementPlus from './plugins/element'
import router from './router'
import store from './store'
import './styles/index.scss' // 我们自己的样式
const app = createApp(App).use(store).use(router)
app.provide('apiUrl', import.meta.env.VITE_APP_BASE_API)
installElementPlus(app)
app.mount('#app')
- 创建一个用于覆盖 Element Plus 样式变量的文件
src/styles/element-variables.scss
:
/* 改变主题色变量 */
$--colors: (
'primary': (
'base': #388E3C,
),
'success': (
'base': #67c23a,
),
'warning': (
'base': #C7D66D,
),
'danger': (
'base': #7C77B9,
),
'error': (
'base': #F6828C,
),
'info': (
'base': #909399,
),
);
/* 必须指明字体图标路径,不然会报错 */
$--font-path: 'element-plus/theme-chalk/fonts';
/* 在主题变量后再导入 element-plus的 scss,避免 sass 混合变量的问题 */
@import 'element-plus/packages/theme-chalk/src/index';
注意 ⚠️:ElementPlus 1.1.0 版之后有一些破坏性改动:
按需引入的情况下,那些必须嵌套使用的子组件,比如el-select
组件内部的el-option
组件、菜单组件的el-menu-item
,都不用再导入了,因为内容已经被集成到父组件内了;
像submenu
不仅目录名改了,只剩下一个style
子文件夹里面的内容也都空了(index.js
等 4 个文件都没有内容)。 要记得把模版中原本的
替换成
。
大致列一下避雷:
ElBreadcrumbItem
、ElDropdownItem
、ElDropdownItem
、ElDropdownMenu
、ElFormItem
、ElMenuItem
、ElOption
、ElRadioGroup
、ElTableColumn
、ElTabPane
...
- 引入自定义主题
scss
并全局注册需要的组件
src/plugins/element.js
:
import {
ElBreadcrumb,
ElButton,
...
ElMessage,
ElMessageBox,
}
const components = [
ElBreadcrumb,
ElButton,
...
ElMessage,
ElMessageBox,
]
const option = { size: 'small', zIndex: 3000 }
import '../styles/element-variables.scss'
export default app => {
// 按需引入时做 element-plus 的全局配置
app.config.globalProperties.$ELEMENT = option
// 注册需要的 element-plus 组件
components.forEach(component => {
app.use(component)
})
}
新版的 ElementPlus 组件全都有install
方法,而1.0.2
的时候只有几个组件有install
,其余要用app.component()
注册全局组件。现在方便了,全部遍历然后直接app.use()
即可。
而且用use()
等于安装插件,那些消息组件就会自动像这样注册全局方法:app.config.globalProperties.$message = _Message
不用担心按需导入就无this.$message
。
- 以及国际化(设置默认语言为中文)的实现:
src/App.vue
:
Home |
User |
About
src/router/index.js
:
import { createRouter, createWebHashHistory } from 'vue-router'
const routes = [
{
path: '/',
name: 'Home',
component: () => import('@views/Home.vue'),
},
{
path: '/user',
name: 'User',
component: () =>
import('@views/User.vue'),
},
{
path: '/404',
component: () => import("page-404" */ '@views/404'),
hidden: true,
},
{
path: '/:pathMatch(.*)*',
name: 'NotFound',
redirect: '/404',
hidden: true,
},
]
const router = createRouter({
scrollBehavior: () => ({
top: 0,
}),
history: createWebHashHistory(),
routes,
})
export default router
src/views/Home.vue
:
调用全局 $message 方式一
调用全局 $message 方式二、三
比自己覆盖 UI 颜色样式轻松多了有木有~