资讯中心

Element Plus在Vue3项目中的接入实践:按需引入、主题定制与踩坑解析

📅 2026/9/29 9:11:35
Element Plus在Vue3项目中的接入实践:按需引入、主题定制与踩坑解析
1. 为什么选 Element Plus迁移背景与组件库选型1.1 从 Vue2 到 Vue3组件库怎么选做后台管理系统这行时间久了Vue 生态里绕不开的组件库就那两三个。前两年主力还是 Vue2 配 Element UI从去年开始新项目基本都切到 Vue3 了。技术面试里 Vue2 和 Vue3 的区别成了高频题团队内部讨论时大家也在评估要不要把存量系统迁过来。当时我把候选方案列了一圈Naive UI、Ant Design Vue、Element Plus还有几个轻量级的替代品挨个做了对比。Naive UI 确实是后起之秀TypeScript 推导做得很到位设计风格也年轻化但团队里没人系统用过遇到冷门问题只能自己趟。Ant Design Vue 体系成熟但很多 API 跟 React 版存在出入我团队的同学以前用 Element UI 写了大量业务代码突然换一套写法熟悉成本摆在那里。Element Plus 是 Element UI 官方推出的 Vue3 版本组件名、API、常用交互模式基本沿袭老项目里的表格、表单、弹窗、分页这些高频组件几乎可以照着原来的写法平移到 Vue3。从团队迁移摩擦和实际交付周期来看Element Plus 是当时综合成本最低的选择。这里补充一个观点组件库没有绝对的好坏适合团队现状才是关键。一个从零开始的团队选 Naive UI 或者 Ant Design Vue 完全没有问题但如果你手头是存量 Element UI 项目要升级或者团队大部分成员写惯了 Element 系列Element Plus 能让你少掉很多头发。1.2 Element Plus 在后台管理系统里的优势后台管理系统和面向 C 端的页面不一样组件需求高度集中表格、表单、弹窗、标签页、面包屑、分页、权限菜单、上传下载。Element Plus 在这几块的覆盖非常完整el-table 的列配置、多级表头、合并单元格、虚拟滚动el-form 的校验规则体系都属于拿来就能用的水平不需要自己造轮子。另一个优势是生态和资料量。因为用户群体大社区博客、面试题、源码解析、二次封装示例都极其丰富。遇到需求搜索引擎里基本能翻到参考实现。再叠加各种后台管理脚手架和平台类项目都在用 Element Plus无论是基于若依的 Vue3 版本还是 JeecgBoot 的前端模块默认 UI 基本都是它这对团队招聘和新人上手也很友好。新同学只要会 Vue3官网翻一翻组件很快就能写起来。2. 动手前准备Node 环境与 Vite 项目初始化2.1 环境版本怎么选接入 Element Plus 之前先把开发环境理清楚。Node 版本建议 16.x 以上我现在主力用的是 Node 18 和 Node 20Vite4、Vite5 都能稳定跑。包管理器我用 npm其实 pnpm、yarn 都行重点注意 lock 文件不要频繁切来切去团队里统一一个就好。Vue3 项目的工程化有两种主流构建方式Vite 和 Webpack。新项目我强烈建议 Vite开发服务器启动速度是真的快热更新体验比 Webpack 时代强太多。有一个概念要提前说清楚Vite 和 Webpack 只是构建工具不改变 Vue 或 Element Plus 的代码写法它们之间的差别主要体现在配置文件以及按需引入插件的使用方式上。网上经常有人问 vue3 vite 和 webpack 选哪个我的建议是新项目无脑选 Vite老项目如果 Webpack 5 跑得稳定没必要为了换而换折腾构建工具的时间不如多写两个业务页面。2.2 用 Vite 创建 Vue3 项目实操直接用官方脚手架创建项目执行下面这条命令npm create vuelatest如果你想要更干净的裸模板也可以用npm create vitelatest my-element-plus-demo -- --template vue我习惯用 create-vue 的向导模式因为它会交互式地问你要不要 TypeScript、Vue Router、Pinia、ESLint 等按需勾选完就生成标准工程结构。做后台管理系统的同学建议把 Vue Router 和 Pinia 都勾上后面做权限、菜单、动态路由都会用到省得再手动补依赖。项目创建完后先验证基础环境cd my-element-plus-demo npm install npm run dev浏览器打开 Vite 输出的本地地址能看到默认的 Vue 欢迎页说明环境没问题。到这里基础工程就绪下一步开始接入 Element Plus。3. 接入 Element Plus 的两种引入方式3.1 全量引入最快跑起来Element Plus 的接入方式分全量引入和按需引入两种。全量引入适合内部后台、管理端这类对首屏体积不敏感、追求开发速度的场景也是新手最容易上手的方式。安装依赖npm install element-plus然后在入口文件里注册import { createApp } from vue import ElementPlus from element-plus import element-plus/dist/index.css import App from ./App.vue const app createApp(App) app.use(ElementPlus) app.mount(#app)完成这一步之后页面里直接写el-button、el-table就能渲染不需要额外 import。全量引入最大的优点是省心写模板的时候不用惦记组件有没有引入全局注册完后所有组件随取随用。缺点自然就是打包体积偏大element-plus 主包加 css 压缩后也有几百 KB但对跑在内网的内部系统来说完全可接受。我第一次接入的时候图省事就是用全量引入从开始装依赖到页面出按钮前后不到十分钟。3.2 按需引入生产环境推荐方案如果项目要部署到公网或者你比较在意首屏性能建议换按需引入。Element Plus 官方现在最推荐的方式是配合 unplugin-auto-import 和 unplugin-vue-components 两个 Vite 插件实现自动导入装依赖npm install element-plus npm install -D unplugin-auto-import unplugin-vue-components然后在 vite.config.js 里配置import { defineConfig } from vite import vue from vitejs/plugin-vue import AutoImport from unplugin-auto-import/vite import Components from unplugin-vue-components/vite import { ElementPlusResolver } from unplugin-vue-components/resolvers export default defineConfig({ plugins: [ vue(), AutoImport({ resolvers: [ElementPlusResolver()] }), Components({ resolvers: [ElementPlusResolver()] }) ] })配置完成后模板里的el-button会在编译阶段被自动收集只把用到的组件和对应样式打进最终产物。像 ElMessage、ElNotification 这类函数式 API 也会自动导入。这里有一个常见的理解偏差很多同学以为引入这两个插件之后代码里还要手动 import 每个组件其实不需要插件做的是编译期自动注册和样式收集源码里直接写标签就行。还要提醒 TypeScript 用户自动导入插件会在项目根目录生成 auto-imports.d.ts 和 components.d.ts 两个声明文件记得确认 tsconfig 的 include 范围把它们包含进去否则编辑器会疯狂报找不到模块。另外ElMessage 这类命令式组件有时会出现“功能正常但样式错乱”的情况多半是样式没被正确收集手动补一句导入即可import element-plus/es/components/message/style/css3.3 全局配置尺寸、语言与 z-index注册 Element Plus 的时候还能传一些全局配置我项目里比较常用这几项import zhCn from element-plus/es/locale/lang/zh-cn app.use(ElementPlus, { size: default, zIndex: 3000, locale: zhCn })size 用来统一控制组件尺寸规格。比如整个项目希望按钮、输入框、表格都紧凑一点直接设成 small比自己逐个组件传 size 高效得多。locale 是界面语言Element Plus 默认英文文案国内项目一定要传 zhCn否则日期选择器面板和分页组件里的“Go to”这类文字都是英文的。zIndex 是层叠上下文基准值如果项目里存在自己的弹窗、浮层组件把 zIndex 调高一些能避免与 Element Plus 的弹窗层级打架。4. 主题定制与暗黑模式4.1 SCSS 变量定制主题方案后台系统一般都要换企业主题色Element Plus 提供两套定制方案SCSS 变量和 CSS 变量。SCSS 方案适合 Vite 加 sass 的工程配置步骤稍微多一点。先安装 sassnpm install -D sass然后建一个主题覆盖文件我习惯放在 styles/element/index.scssforward element-plus/theme-chalk/src/common/var.scss with ( $colors: ( primary: ( base: #2f6fed, ), ), );这里用 forward 配合 with 的写法是 element-plus 样式包提供给外部覆盖变量的入口如果你在网上翻到老的 import 方式在新样式结构下已经失效。接着在 vite.config.js 里把文件注入到全局 scss 预处理上下文css: { preprocessorOptions: { scss: { additionalData: use /styles/element/index.scss as *; } } }注意 additionalData 里用的是 use 而不是 import这里只是把变量文件注入到每个 scss 模块的编译上下文。配置完重启 dev server主色会全局变化。这里必须强调一个容易踩的坑SCSS 变量方案能生效的前提是组件样式走 sass 编译入口。如果你用的是按需引入插件resolver 也要跟着改ElementPlusResolver({ importStyle: sass })否则组件样式引的依然是编译好的 css 产物SCSS 变量根本进不去主题色永远不会变。我当时在这个问题上卡了一下午最后发现是 resolver 漏改了这个细节很多文章都没写清楚。4.2 CSS 变量方案与暗黑模式如果项目只需要做一两个主题色切换或者要上暗黑模式CSS 变量方案更直观。Element Plus 的组件样式基于 --el-color-primary 这类 CSS 变量构建所以全局覆盖变量即可:root { --el-color-primary: #2f6fed; }暗黑模式官方文档有明确支持路径。先引入暗黑模式样式文件再给根节点 html 加上 dark classimport element-plus/theme-chalk/dark/css-vars.csshtml.dark { background: #0d1117; }动态切换可以用 vueuse/core 的 useDark它会自动操作 html 的 classimport { useDark, useToggle } from vueuse/core const isDark useDark() const toggleDark useToggle(isDark)在后台系统里我一般把切换按钮绑上 toggleDark同时用 localStorage 持久化用户偏好。CSS 变量方案的好处是运行时切换不需要重新编译 sass非常适合线上需要用户自主换肤的场景。4.3 修改组件样式以 tabs 标签页为例后台管理系统里经常要改组件样式网上搜索率很高的就是 vue3 修改 tabs 标签页样式。这里给出三层递进的通用套路学会了能覆盖大部分组件微调需求。第一层是全局覆盖。给 el-tabs 外层添加自定义 class然后写.custom-tabs .el-tabs__item { height: 40px; line-height: 40px; }第二层是利用 CSS 变量。Element Plus 为 tabs 暴露了 --el-tabs-header-height 这类变量直接覆盖变量比逐个 class 微调更稳定比如.custom-tabs { --el-tabs-header-height: 42px; }第三层是深度选择器。如果组件内部结构嵌套较深scoped 样式选不中内部节点需要配合:deep()style scoped .custom-tabs :deep(.el-tabs__nav-wrap) { background: #f5f7fa; border-radius: 6px; } /style这三个层级按需组合能解决绝大多数组件样式定制需求。要注意 scoped 样式里直接写 .el-tabs__item 是选不中组件内部 DOM 的必须外包装一个父级类名再用 :deep() 穿透这是 Vue3 scoped 样式机制决定的。5. 高频踩坑与问题排查实录5.1 TS 报错与版本兼容问题先聊 TypeScript 场景。很多朋友用若依的 Vue3 版本或者 JeecgBoot 这类平台做二次开发启动时经常遇到 TS 报错。最常见的两类一是模板里访问 globalProperties 上挂的方法或属性时没有类型声明比如 $modal、$notice二是按需引入插件生成的 components.d.ts 没有被 tsconfig 包含。前者的解决方式是在 src/types 下建一个声明文件import { ComponentCustomProperties } from vue declare module vue { interface ComponentCustomProperties { $modal: any $notice: any } } export {}后者处理方式更简单把 auto-imports.d.ts 和 components.d.ts 加进 tsconfig 的 include或者直接保证它们被提交进 Git 仓库团队其他人拉代码后编辑器就能正确识别不用每次重新生成。版本兼容问题上注意 element-plus 的 major 版本要跟 Vue3 严格匹配Element Plus 只支持 Vue3不能用在 Vue2 项目里。如果你还在维护 Vue2 老系统老老实实用 Element UI别硬上。5.2 样式没生效、图标不显示样式问题的经典场景有两个。一是全量引入时 index.css 引入顺序和后置覆盖顺序不对导致自定义样式被组件样式反压二是按需引入时某个组件的样式没有被自动收集。排查思路是先确认 resolver 配置正确再看编译产物里到底有没有对应组件的样式 chunk。如果用的是全量引入检查入口文件里import element-plus/dist/index.css这一行是否在自定义全局样式之前顺序颠倒会出问题。图标不显示也是高频问题。Element Plus 的图标从早期的字体文件换成了 SVG 组件不再支持全局一次性注入全部图标官方推荐用 SvgIcon 或者按需注册。我一般在入口文件统一注册项目用到的图标import { Edit, Delete, Search, Refresh } from element-plus/icons-vue const app createApp(App) app.component(Edit, Edit) app.component(Delete, Delete) app.component(Search, Search) app.component(Refresh, Refresh)模板里配合 el-icon 使用el-iconEdit //el-icon图标不显示的原因九成是只引了组件没引 ElementPlusIconsVue或者注册名跟模板标签名不一致检查这两点基本能解决。5.3 联动场景路由跳转不渲染、echarts 被 px2rem 影响路由跳转后组件内容渲染不显示这是个老生常谈的问题。我排查过几次最常见的原因是多个页面复用了同一个组件实例或者 keep-alive 缓存导致组件没有重新触发初始化逻辑。解决方案是监听 route 变化watch( () route.path, () { // 重新加载数据 } )如果确认是 keep-alive 缓存导致页面残留考虑用 :key 强制重建router-view v-slot{ Component } keep-alive component :isComponent :keyroute.fullPath / /keep-alive /router-view另一个典型的联动问题是做移动端或者大屏项目时用 pxtorem 做 rem 适配结果 echarts 的尺寸不对。网上搜 vue3 pxtorem 对 echarts 没起到效果本质不是 echarts 的问题而是 rem 换算后 echarts 初始化时拿到的容器宽高不对甚至初始化时容器还没渲染完。常见处理是监听容器尺寸变化并调用 chart.resize()const resizeObserver new ResizeObserver(() { chart.resize() }) resizeObserver.observe(containerEl)另外 echarts 初始化最好放在 nextTick 里确保容器渲染完成后再获取尺寸否则拿到的经常是 0。这两个问题单看和 Element Plus 无关但后台管理系统基本都是 Element Plus 布局加图表页面的组合联调时经常一起出现整理成速查给团队节省了不少排查时间。5.4 常见问题速查表问题现象概率原因解决动作主题色修改不生效resolver 未配 importStyle: sass检查 ElementPlusResolver 配置ElMessage 样式错乱样式未被自动收集手动 import message/style/cssTS 报找不到组件components.d.ts 未生成或未包含提交 d.ts 并加入 tsconfig include图标显示为方块图标组件未注册统一注册或按需 import 图标tabs 自定义样式失效scoped 下未用 :deep()外层加 class 配合 :deep() 穿透路由跳转组件不刷新keep-alive 缓存或实例复用监听 route 或 :key 强制重建echarts 显示尺寸异常px2rem 导致容器宽高不对用 ResizeObserver 调用 chart.resize()6. 接入后的性能优化与实战经验6.1 打包体积与首屏优化接入 Element Plus 后构建体积会有明显上升。全量引入模式下element-plus 主包加样式可能在 Gzip 前接近 1MB所以对外项目建议按需引入。除此之外还可以在 Vite 里拆分 vendor chunk把 element-plus 单独抽成一个包配合浏览器缓存首屏加载虽然要下载但后续页面切换资源命中缓存体验会好不少build: { rollupOptions: { output: { manualChunks: { element-plus: [element-plus], echarts: [echarts] } } } }如果业务里有大表格或者长列表建议用 el-table-v2 虚拟表格。Element Plus 提供的虚拟表格组件渲染几千行数据没有压力比普通 el-table 配一堆分页更流畅。实测下来对实时监控类场景el-table-v2 配合定时刷新数据CPU 占用稳定很多不会有明显的滚动卡顿。6.2 二次封装表格、表单与弹窗接完 Element Plus我个人强烈建议做一层业务组件的二次封装。后台管理系统页面重复度太高直接裸写 el-table、el-form 会很累。我维护的项目里封装了一个 ProTable 组件内部统一处理请求、loading、分页、操作列页面里只需要传列配置和接口地址ProTable :columnscolumns :requestfetchList /类似的还有 ProForm、DialogPage 这类封装。这层封装的价值在于把 Element Plus 的组件能力包装成适合自己业务形态的接口后续业务开发效率会成倍提升。如果你是在若依或者 JeecgBoot 这类平台上开发它内部已经做了大量类似封装接完 Element Plus 直接用于业务即可不用从底层再封装一套。6.3 最后分享一点实操心得接入完成后我习惯在项目里花半天时间把官方文档的组件全预览跑一遍重点看表单、表格、对话框、消息提示这几类高频组件把默认交互和样式提前确认好避免开发到一半发现某个组件行为不符合预期再到处改。另外就是 element-plus 的版本不要频繁升UI 组件库这类基础设施稳定优先除非有必须修复的 bug 或者需要新特性一般锁住版本不动。确需升级时提前看 release notes 里有没有 breaking change升级完把表格、表单、弹窗、日期选择器这些核心组件都回归一遍再上线。这几条经验看着简单但真能帮你少踩很多不必要的坑。

看完文章,想为自己的企业也做一次专业网站诊断?

尧图顾问免费为您评估现有网站,并给出建站/改版建议与报价方案。

免费获取方案