【Element Plus + VXE-Table】实战:从选型规范到落地实操,彻底搞懂组件库高效用法,避开样式冲突、维护混乱等高频坑!

📑 文章目录
- 一、为什么需要统一规范?
- [1.1 常见问题](#1.1 常见问题)
- [1.2 规范能带来什么](#1.2 规范能带来什么)
- 二、技术选型:什么时候用谁?
- [2.1 Element Plus 和 VXE-Table 的定位](#2.1 Element Plus 和 VXE-Table 的定位)
- [2.2 选型决策图(简化版)](#2.2 选型决策图(简化版))
- [三、Element Plus 使用规范](#三、Element Plus 使用规范)
- [3.1 按需引入 vs 全量引入](#3.1 按需引入 vs 全量引入)
- [3.2 全局样式覆盖规范](#3.2 全局样式覆盖规范)
- [3.3 命名与类名前缀约定](#3.3 命名与类名前缀约定)
- [四、VXE-Table 使用规范](#四、VXE-Table 使用规范)
- [4.1 按需引入](#4.1 按需引入)
- [4.2 复杂表格示例](#4.2 复杂表格示例)
- [4.3 与 Element Plus 的样式隔离](#4.3 与 Element Plus 的样式隔离)
- 五、统一封装:减少重复、统一行为
- [5.1 封装通用表格组件思路](#5.1 封装通用表格组件思路)
- [5.2 表单封装示例](#5.2 表单封装示例)
- 六、常见踩坑与解决
- [6.1 样式不生效](#6.1 样式不生效)
- [6.2 VXE-Table 与 Element Plus 样式互相覆盖](#6.2 VXE-Table 与 Element Plus 样式互相覆盖)
- [6.3 按需引入后打包体积仍然偏大](#6.3 按需引入后打包体积仍然偏大)
- [6.4 表格数据更新但界面不刷新](#6.4 表格数据更新但界面不刷新)
- 七、工程化落地清单
- [7.1 项目初始化](#7.1 项目初始化)
- [7.2 编码约定](#7.2 编码约定)
- [7.3 文档与协作](#7.3 文档与协作)
- 八、总结
- 附录:快速参考
- [🔍 系列模块导航](#🔍 系列模块导航)
- [📝 工程化与协作规范](#📝 工程化与协作规范)
- [📚 系列总览](#📚 系列总览)
同学们好,我是 Eugene(尤金),一名多年中后台前端开发工程师。
(Eugene 发音 /juːˈdʒiːn/,大家怎么顺口怎么叫就好)
很多前端开发者都会遇到一个瓶颈:
代码能跑,但不够规范;功能能实现,但维护起来特别痛苦;一个人写没问题,一到团队协作就各种混乱、踩坑、返工。
想写出干净、优雅、可维护 的专业代码,靠的不是天赋,而是体系化的规范 + 真实实战经验。
这一系列《前端规范实战》,我会用大白话 + 真实业务场景,不讲玄学、不堆理论,只分享能直接落地的规范、标准与避坑指南。
帮你从「会写代码」真正升级为「会写优质、可维护、团队级别的代码」。
一、为什么需要统一规范?
1.1 常见问题
- 样式冲突:多人各写各的,类名、变量、覆盖方式不统一
- 心智负担 :有的用
el-table,有的用vxe-table,新人难上手 - 打包冗余:按需引入不规范,全量引入导致体积过大
[⬆ 返回目录](#⬆ 返回目录)
1.2 规范能带来什么
- 样式统一、可预期
- 新成员上手快
- 减少重复造轮子
- 降低维护成本
[⬆ 返回目录](#⬆ 返回目录)
二、技术选型:什么时候用谁?
2.1 Element Plus 和 VXE-Table 的定位
| 场景 | 推荐 | 理由 |
|---|---|---|
| 表单、弹窗、按钮、布局 | Element Plus | 基础组件完备、生态成熟 |
| 复杂表格(多选、树、合并、虚拟滚动) | VXE-Table | 表格能力强 |
| 简单表格(列少、无复杂交互) | Element Plus el-table | 足够用,依赖少 |
原则:基础表单用 Element Plus,复杂表格用 VXE-Table,简单表格用 el-table。
[⬆ 返回目录](#⬆ 返回目录)
2.2 选型决策图(简化版)
Plain
需求:需要一个表格
↓
是否有以下任一情况?
- 列很多(>20)需要虚拟滚动
- 树形数据
- 复杂合并单元格
- 可编辑表格、复杂筛选
↓
是 → 用 VXE-Table
否 → 用 Element Plus el-table
[⬆ 返回目录](#⬆ 返回目录)
三、Element Plus 使用规范
3.1 按需引入 vs 全量引入
建议:按需自动引入(unplugin-vue-components + unplugin-auto-import)
js
// vite.config.js
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
export default {
plugins: [
AutoImport({
resolvers: [ElementPlusResolver()],
dts: 'src/auto-imports.d.ts',
}),
Components({
resolvers: [ElementPlusResolver()],
dts: 'src/components.d.ts',
}),
],
}
效果:组件和 API 无需手动 import,直接使用,且只打包用到的组件。
[⬆ 返回目录](#⬆ 返回目录)
3.2 全局样式覆盖规范
不建议到处写 !important 覆盖,建议集中用 CSS 变量或统一覆盖文件。
css
// styles/element-override.scss
// 1. 通过 CSS 变量统一改主题
:root {
--el-color-primary: #409eff;
--el-border-radius-base: 4px;
}
// 2. 针对特定组件的覆盖,加项目前缀避免污染
.my-project {
.el-button--primary {
border-radius: 8px;
}
.el-table {
--el-table-border-color: #e4e7ed;
--el-table-header-bg-color: #f5f7fa;
}
}
[⬆ 返回目录](#⬆ 返回目录)
3.3 命名与类名前缀约定
统一使用项目级类名前缀,方便排查样式、避免污染:
html
<template>
<div class="order-page">
<el-form class="order-page__form" />
<el-table class="order-page__table" />
</div>
</template>
<style scoped lang="scss">
.order-page {
&__form { /* 表单样式 */ }
&__table { /* 表格样式 */ }
}
</style>
[⬆ 返回目录](#⬆ 返回目录)
四、VXE-Table 使用规范
4.1 按需引入
js
// main.js 或 plugins/vxe-table.js
import { createApp } from 'vue'
import App from './App.vue'
// 按需引入 VXE-Table
import VXETable from 'vxe-table'
import 'vxe-table/lib/style.css'
// 如果用到表单等扩展
// import VxeTablePluginElement from 'vxe-table-plugin-element'
// import 'vxe-table-plugin-element/dist/style.css'
// VXETable.use(VxeTablePluginElement)
createApp(App).use(VXETable).mount('#app')
表格简单时,可按需引入具体子模块,进一步减小体积。
[⬆ 返回目录](#⬆ 返回目录)
4.2 复杂表格示例
下面是一个带多选、树形、合并单元格的示例,演示 VXE-Table 常用配置和用法:
html
<template>
<div class="product-table">
<vxe-table
ref="tableRef"
:data="tableData"
:tree-config="{ children: 'children' }"
:span-method="spanMethod"
:checkbox-config="{ checkRowKeys: selectedRows }"
@checkbox-change="onSelectChange"
>
<vxe-column type="checkbox" width="60" />
<vxe-column field="name" title="名称" tree-node />
<vxe-column field="category" title="分类" />
<vxe-column field="price" title="价格" />
<vxe-column field="stock" title="库存" />
</vxe-table>
</div>
</template>
<script setup>
import { ref, reactive } from 'vue'
const tableRef = ref(null)
const selectedRows = ref([])
const tableData = reactive([
{
id: 1,
name: '电子产品',
category: '一级',
price: '-',
stock: '-',
children: [
{ id: 2, name: '手机', category: '二级', price: 3999, stock: 100 },
{ id: 3, name: '电脑', category: '二级', price: 6999, stock: 50 },
],
},
])
// 合并单元格:相同分类合并
const spanMethod = ({ row, columnIndex }) => {
if (columnIndex === 1) {
// 可根据业务逻辑返回 [rowspan, colspan]
return [1, 1]
}
return [1, 1]
}
const onSelectChange = () => {
selectedRows.value = tableRef.value?.getCheckboxRecords() || []
}
</script>
<style scoped lang="scss">
.product-table {
:deep(.vxe-table) {
// 使用 :deep() 穿透 scoped 修改 VXE 内部样式
.vxe-header--column {
background-color: #f5f7fa;
}
}
}
</style>
[⬆ 返回目录](#⬆ 返回目录)
4.3 与 Element Plus 的样式隔离
两个库都带自己的样式,需要控制作用域,避免互相影响:
css
// 方案1:用父级包裹,限定 VXE 样式范围
.vxe-container {
.vxe-table {
/* 只在这个容器内生效 */
}
}
// 方案2:提高选择器权重,避免被 Element 覆盖
.product-table.vxe-table-wrapper {
.vxe-table--render-default {
border: 1px solid #dcdfe6;
}
}
[⬆ 返回目录](#⬆ 返回目录)
五、统一封装:减少重复、统一行为
5.1 封装通用表格组件思路
把表格通用逻辑抽成组件,内部根据 type 决定用 el-table 还是 vxe-table,对外统一 API。
html
<!-- components/CommonTable/index.vue -->
<template>
<!-- 简单表格用 el-table -->
<el-table
v-if="tableType === 'simple'"
:data="data"
v-bind="$attrs"
v-on="$listeners"
>
<el-table-column
v-for="col in columns"
:key="col.prop"
:prop="col.prop"
:label="col.label"
:width="col.width"
/>
</el-table>
<!-- 复杂表格用 vxe-table -->
<vxe-table
v-else
:data="data"
v-bind="$attrs"
>
<vxe-column
v-for="col in columns"
:key="col.prop"
:field="col.prop"
:title="col.label"
:width="col.width"
/>
</vxe-table>
</template>
<script setup>
defineProps({
tableType: {
type: String,
default: 'simple', // 'simple' | 'complex'
},
data: {
type: Array,
default: () => [],
},
columns: {
type: Array,
required: true,
},
})
</script>
业务侧只需传 tableType、data、columns,不用关心内部用的是谁。
[⬆ 返回目录](#⬆ 返回目录)
5.2 表单封装示例
html
<!-- components/CommonForm/index.vue -->
<template>
<el-form
ref="formRef"
:model="formData"
:rules="rules"
label-width="100px"
class="common-form"
>
<el-form-item
v-for="item in formConfig"
:key="item.prop"
:label="item.label"
:prop="item.prop"
>
<el-input
v-if="item.type === 'input'"
v-model="formData[item.prop]"
:placeholder="item.placeholder"
/>
<el-select
v-else-if="item.type === 'select'"
v-model="formData[item.prop]"
:options="item.options"
placeholder="请选择"
/>
</el-form-item>
</el-form>
</template>
<script setup>
const props = defineProps({
formConfig: { type: Array, required: true },
rules: { type: Object, default: () => ({}) },
})
const formData = reactive({})
const formRef = ref(null)
// 暴露校验、重置等方法
defineExpose({
validate: () => formRef.value?.validate(),
resetFields: () => formRef.value?.resetFields(),
})
</script>
[⬆ 返回目录](#⬆ 返回目录)
六、常见踩坑与解决
6.1 样式不生效
现象 :改了 .el-table 样式,页面无变化。
原因 :scoped 限制或选择器优先级不够。
处理 :使用 :deep() 或统一在非 scoped 的覆盖文件中写。
css
// 错误:scoped 下可能选不中
.my-page .el-table { }
// 正确:穿透到子组件
.my-page :deep(.el-table) {
.el-table__header th {
background: #f5f7fa;
}
}
[⬆ 返回目录](#⬆ 返回目录)
6.2 VXE-Table 与 Element Plus 样式互相覆盖
现象:两个库的按钮、输入框等样式混在一起。
处理:
- 统一引入顺序:先 Element,再 VXE
- 用父级容器限制 VXE 样式作用范围
- 必要时提高选择器权重或使用更具体的类名
[⬆ 返回目录](#⬆ 返回目录)
6.3 按需引入后打包体积仍然偏大
检查:是否全量引入了某个库或样式。
js
// 不推荐:全量引入
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
app.use(ElementPlus)
// 推荐:配合 unplugin 按需引入,无需手动 import 组件
[⬆ 返回目录](#⬆ 返回目录)
6.4 表格数据更新但界面不刷新
现象 :用索引改数组 arr[0].name = 'xx',表格不更新。
处理:用响应式 API 或替换整个数组,触发更新。
js
// 不推荐
tableData[0].name = '新名字'
// 推荐
tableData[0] = { ...tableData[0], name: '新名字' }
// 或
tableData.splice(0, 1, { ...tableData[0], name: '新名字' })
[⬆ 返回目录](#⬆ 返回目录)
七、工程化落地清单
7.1 项目初始化
- 统一引入方式(按需 / 全量)
- 新建
styles/element-override.scss集中覆盖 Element 样式 - 新建
styles/vxe-override.scss集中覆盖 VXE 样式 - 在
main.js中按固定顺序引入样式
[⬆ 返回目录](#⬆ 返回目录)
7.2 编码约定
- 页面/模块使用统一类名前缀(如
order-page) - 覆盖样式写在
:deep()或集中覆盖文件中 - 复杂表格统一用 VXE,简单表格用 el-table
- 通用表格、表单做成组件,内部统一实现
[⬆ 返回目录](#⬆ 返回目录)
7.3 文档与协作
- 在项目 README 或内部文档中写明:选型原则、引入方式、覆盖规范
- Code Review 时检查是否符合规范
[⬆ 返回目录](#⬆ 返回目录)
八、总结
| 要点 | 建议 |
|---|---|
| 选型 | 基础表单用 Element Plus,复杂表格用 VXE-Table |
| 引入 | Element 使用 unplugin 按需引入,VXE 按需引入所需模块 |
| 样式 | 集中覆盖、使用 :deep()、统一类名前缀 |
| 封装 | 通用表格/表单抽成组件,对外统一 API |
| 避坑 | 注意引入顺序、响应式更新、选择器优先级 |
规范的价值在于:一开始多花一点时间定好规矩,后续开发和维护会轻松很多。如果你有自己项目中的具体问题,欢迎在评论区交流。
[⬆ 返回目录](#⬆ 返回目录)
附录:快速参考
Element Plus 常用组件
- 表单:
el-form、el-form-item、el-input、el-select - 表格:
el-table、el-table-column - 弹窗:
el-dialog - 布局:
el-row、el-col
VXE-Table 常用能力
- 树形:
tree-config - 合并:
span-method - 多选:
checkbox-config、type="checkbox" - 虚拟滚动:
height+ 大数据量
[⬆ 返回目录](#⬆ 返回目录)
🔍 系列模块导航
📝 工程化与协作规范
一、《Vite 工程化实战:alias/env/proxy/ 打包配置全解析,统一项目规范避坑|工程化与协作规范篇》
二、《前端多环境配置规范:dev/test/pre/prod 环境差异与配置,避免生产环境踩坑|工程化与协作规范篇》
三、《前端 Git 协作规范实战:commit message + 分支管理 + 合并流程,告别冲突与混乱|工程化与协作规范篇》
四、《ESLint + Prettier 实战:统一前端代码风格,自动修复语法格式问题|工程化与协作规范篇》
五、《Element Plus/VXE-Table UI 组件库规范:统一用法实战,避开样式冲突与维护混乱|工程化与协作规范篇》
👉 跟着系列慢慢学,把技术功底扎扎实实地打牢~
📚 系列总览
前端体系化学习完全体:基础 → 规范 → 架构 → 大厂面试
四套系列、百余篇高质量实战文,从入门到进阶,一站式补齐前端核心能力
- 前端基础实战系列 : 《前端基础实战:JS/TS与Vue体系化扫盲(47 篇完整目录 + 避坑)》
- 前端规范实战系列 : 《JS/TS/Vue 前端规范实战:从写对到写优,搞定中后台规范落地,打造可维护代码(40 篇全目录)》
- 前端架构实战系列:聚焦工程化、性能优化、可维护架构、中后台体系设计(持续更新中)
- 前端大厂面试系列:覆盖高频考点、手写题、项目深挖、简历与面试技巧(规划中)
每个系列完结后,都会整理成一篇完整导航文并附上直达链接,方便大家按顺序、体系化学习。
全套内容持续更新中,敬请期待~
技术成长,从来不是比谁写得快,而是比谁写得稳、规范、可维护。
哪怕每次只吃透一条规范,长期下来,差距会非常明显。
后续我会持续更新前端规范、工程化、可维护代码相关实战干货,帮你告别面条代码、维护噩梦,在开发与面试中更有底气。
觉得有用欢迎 点赞 + 收藏 + 关注,不错过每一篇实战内容。
我是 Eugene,与你一起写规范、写优质代码,我们下篇干货见~