在Vue生态中,Element系列组件库无疑是最受欢迎的UI解决方案之一。从最初为Vue 2设计的Element,到后来适配Vue 3的Element Plus,两者既有传承又有革新。
一、Element与Element Plus的核心区别
Element(全称Element UI)诞生于2016年,是饿了么前端团队推出的基于Vue 2的桌面端组件库;而Element Plus则是2020年随着Vue 3发布而推出的升级版本。两者的区别主要体现在以下几个方面:
1. 框架适配差异
- Element:仅支持Vue 2,基于Options API设计,无法直接在Vue 3项目中使用
- Element Plus:专为Vue 3打造,全面支持Composition API,兼容Vue 3的所有新特性(如Teleport、Suspense等)
2. 技术栈升级
- Element:使用Vue 2的响应式系统(Object.defineProperty),依赖Vue 2的内部API
- Element Plus:采用Vue 3的响应式系统(Proxy),基于Vue 3的Composition API重构,支持Tree-shaking减小打包体积
3. 组件变化
- 新增组件:Element Plus增加了如
ElAvatar
、ElSkeleton
、ElEmpty
、ElAffix
等实用组件 - 组件拆分:部分组件进行了拆分,如Element的
ElSelect
的远程搜索功能在Element Plus中拆分为ElSelectV2
- 功能增强:许多组件增加了新功能,如
ElTable
支持虚拟滚动、ElForm
支持更灵活的校验规则
4. 样式系统
- Element:基于Less编写样式,主题定制需要修改Less变量
- Element Plus:同时支持Less和Sass,提供了更灵活的主题定制方案,支持CSS变量实时切换主题
5. 国际化支持
- Element:支持多语言,但配置方式相对繁琐
- Element Plus:重构了国际化系统,支持按需加载语言包,切换更灵活
6. 类型支持
- Element:缺乏完整的TypeScript类型定义,类型提示不完善
- Element Plus:使用TypeScript重写,提供完整的类型定义,大幅提升开发体验
二、Vue项目中使用Element Plus的详细步骤
1. 环境准备
首先确保你的开发环境满足以下要求:
- Node.js 14.0+
- Vue 3.0+
- 包管理器(npm、yarn或pnpm)
2. 创建Vue 3项目
如果还没有Vue项目,可以使用Vue CLI或Vite创建:
**使用Vite创建(推荐)**:
# 创建项目
npm create vite@latest my-element-plus-app -- --template vue# 进入项目目录
cd my-element-plus-app# 安装依赖
npm install
3. 安装Element Plus
方式一:完整安装(适合快速原型开发)
npm install element-plus --save
方式二:按需安装(适合生产环境,减小打包体积)
npm install element-plus --save
npm install unplugin-vue-components unplugin-auto-import -D
4. 配置Element Plus
完整引入(main.js)
import { createApp } from 'vue'
import App from './App.vue'
// 引入Element Plus
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
// 引入中文语言包
import zhCn from 'element-plus/dist/locale/zh-cn.mjs'const app = createApp(App)// 全局注册
app.use(ElementPlus, {locale: zhCn, // 配置默认语言
})app.mount('#app')
按需引入(vite.config.js)
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// 引入Element Plus按需加载插件
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(),// 自动导入Element Plus相关函数AutoImport({resolvers: [ElementPlusResolver()],}),// 自动注册Element Plus组件Components({resolvers: [ElementPlusResolver()],}),],
})
5. 基本使用示例
示例1:按钮与表单组件
<template><div class="demo-container"><h2>基础组件示例</h2><!-- 按钮组件 --><el-row :gutter="20" class="mb-4"><el-col :span="4"><el-button type="primary">主要按钮</el-button></el-col><el-col :span="4"><el-button type="success">成功按钮</el-button></el-col><el-col :span="4"><el-button type="warning">警告按钮</el-button></el-col><el-col :span="4"><el-button type="danger">危险按钮</el-button></el-col></el-row><!-- 表单组件 --><el-card><el-form :model="form" :rules="rules" ref="formRef" label-width="100px"class="demo-form"><el-form-item label="用户名" prop="username"><el-input v-model="form.username"></el-input></el-form-item><el-form-item label="密码" prop="password"><el-input type="password" v-model="form.password"></el-input></el-form-item><el-form-item label="爱好" prop="hobbies"><el-checkbox-group v-model="form.hobbies"><el-checkbox label="读书"></el-checkbox><el-checkbox label="运动"></el-checkbox><el-checkbox label="游戏"></el-checkbox></el-checkbox-group></el-form-item><el-form-item><el-button type="primary" @click="submitForm">提交</el-button><el-button @click="resetForm">重置</el-button></el-form-item></el-form></el-card></div>
</template><script setup>
import { ref, reactive } from 'vue'// 表单数据
const form = reactive({username: '',password: '',hobbies: []
})// 表单规则
const rules = reactive({username: [{ required: true, message: '请输入用户名', trigger: 'blur' },{ min: 3, max: 10, message: '长度在 3 到 10 个字符', trigger: 'blur' }],password: [{ required: true, message: '请输入密码', trigger: 'blur' },{ min: 6, message: '密码长度不能少于 6 个字符', trigger: 'blur' }],hobbies: [{ required: true, message: '请至少选择一个爱好', trigger: 'change' }]
})// 表单引用
const formRef = ref(null)// 提交表单
const submitForm = () => {formRef.value.validate((valid) => {if (valid) {// 表单验证通过,处理提交逻辑console.log('表单数据:', form)// 这里可以添加API请求等逻辑} else {console.log('表单验证失败')return false}})
}// 重置表单
const resetForm = () => {formRef.value.resetFields()
}
</script><style scoped>
.demo-container {padding: 20px;
}.mb-4 {margin-bottom: 16px;
}.demo-form {width: 600px;
}
</style>
示例2:表格与分页组件
<template><div class="table-demo"><el-card><div class="flex justify-between mb-4"><h2>用户列表</h2><el-button type="primary" @click="showAddDialog = true">新增用户</el-button></div><!-- 搜索区域 --><el-input v-model="searchKeyword" placeholder="请输入用户名搜索" prefix-icon="Search"class="mb-4"@keyup.enter="handleSearch"><template #append><el-button @click="handleSearch" type="primary">搜索</el-button></template></el-input><!-- 表格组件 --><el-table :data="tableData" border stripe :loading="loading"style="width: 100%"><el-table-column prop="id" label="ID" width="80"align="center"></el-table-column><el-table-column prop="name" label="姓名" align="center"></el-table-column><el-table-column prop="age" label="年龄" width="100"align="center"></el-table-column><el-table-column prop="gender" label="性别" width="100"align="center"><template #default="scope"><el-tag :type="scope.row.gender === '男' ? 'info' : 'success'">{{ scope.row.gender }}</el-tag></template></el-table-column><el-table-column prop="email" label="邮箱" align="center"></el-table-column><el-table-column label="操作" width="200"align="center"><template #default="scope"><el-button size="small" type="primary" @click="handleEdit(scope.row)">编辑</el-button><el-button size="small" type="danger" @click="handleDelete(scope.row.id)"style="margin-left: 5px">删除</el-button></template></el-table-column></el-table><!-- 分页组件 --><div class="pagination-container" v-if="total > 0"><el-paginationv-model:current-page="currentPage"v-model:page-size="pageSize":page-sizes="[10, 20, 50]":total="total"layout="total, sizes, prev, pager, next, jumper"@size-change="handleSizeChange"@current-change="handleCurrentChange"></el-pagination></div></el-card></div>
</template><script setup>
import { ref, reactive, onMounted } from 'vue'
import { ElMessage } from 'element-plus'// 表格数据
const tableData = ref([])
// 加载状态
const loading = ref(false)
// 总条数
const total = ref(0)
// 当前页码
const currentPage = ref(1)
// 每页条数
const pageSize = ref(10)
// 搜索关键词
const searchKeyword = ref('')// 页面加载时获取数据
onMounted(() => {fetchTableData()
})// 获取表格数据
const fetchTableData = () => {loading.value = true// 模拟API请求setTimeout(() => {// 模拟数据const mockData = Array.from({ length: pageSize.value }, (_, i) => ({id: (currentPage.value - 1) * pageSize.value + i + 1,name: `用户${(currentPage.value - 1) * pageSize.value + i + 1}`,age: Math.floor(Math.random() * 30) + 18,gender: Math.random() > 0.5 ? '男' : '女',email: `user${(currentPage.value - 1) * pageSize.value + i + 1}@example.com`}))tableData.value = mockDatatotal.value = 100 // 模拟总条数loading.value = false}, 500)
}// 搜索
const handleSearch = () => {currentPage.value = 1 // 重置到第一页fetchTableData()
}// 页码改变
const handleCurrentChange = (val) => {currentPage.value = valfetchTableData()
}// 每页条数改变
const handleSizeChange = (val) => {pageSize.value = valcurrentPage.value = 1 // 重置到第一页fetchTableData()
}// 编辑
const handleEdit = (row) => {ElMessage.info(`编辑用户: ${row.name}`)// 编辑逻辑...
}// 删除
const handleDelete = (id) => {// 确认删除ElMessage.success(`删除用户ID: ${id}`)// 删除逻辑...
}
</script><style scoped>
.table-demo {padding: 20px;
}.pagination-container {margin-top: 16px;text-align: right;
}.flex {display: flex;
}.justify-between {justify-content: space-between;
}.mb-4 {margin-bottom: 16px;
}
</style>
6. 主题定制
Element Plus支持通过CSS变量轻松定制主题,示例如下:
<template><div class="theme-demo"><el-button type="primary">主要按钮</el-button><el-button type="success">成功按钮</el-button><el-switch v-model="isDark" @change="changeTheme"></el-switch><span>{{ isDark ? '深色模式' : '浅色模式' }}</span></div>
</template><script setup>
import { ref } from 'vue'// 深色模式开关
const isDark = ref(false)// 切换主题
const changeTheme = (value) => {const html = document.documentElementif (value) {// 深色模式html.style.setProperty('--el-color-primary', '#722ed1')html.style.setProperty('--el-bg-color', '#141414')html.style.setProperty('--el-text-color-primary', '#ffffff')} else {// 恢复默认html.style.removeProperty('--el-color-primary')html.style.removeProperty('--el-bg-color')html.style.removeProperty('--el-text-color-primary')}
}
</script><style scoped>
.theme-demo {padding: 20px;transition: background-color 0.3s;
}.theme-demo :deep(.el-switch) {margin: 0 10px;
}
</style>