Vue3 + Element Plus 完整使用指南
一、Element Plus 是什么?
Element Plus 是饿了么团队为 Vue 3 打造的一套桌面端 UI 组件库。它是 Element UI 的 Vue 3 版本,提供了丰富的组件,比如按钮、表单、表格、分页、弹窗等,能让你快速搭建出美观的管理后台。
二、安装
2.1 创建 Vue 3 项目(如已有项目可跳过)
bash
npm create vite@latest my-project -- --template vue
cd my-project
npm install
2.2 安装 Element Plus
bash
npm install element-plus
三、引入方式(两种)
方式一:全量引入(推荐新手使用)
在 main.js 中一次性引入所有组件:
js
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> 等标签即可。
缺点:打包体积较大,因为所有组件都会被打包进去。
方式二:按需引入(适合生产项目)
只引入你实际使用的组件,减小打包体积:
js
import { createApp } from 'vue'
import { ElButton, ElTable, ElInput } from 'element-plus'
import 'element-plus/dist/index.css'
import App from './App.vue'
const app = createApp(App)
app.use(ElButton)
app.use(ElTable)
app.use(ElInput)
app.mount('#app')
💡 更推荐搭配
unplugin-vue-components和unplugin-auto-import实现自动按需引入,无需手动 import。
四、常用组件实战
下面以一个「人员信息管理系统」为例,演示常用组件的用法。
4.1 按钮(el-button)
html
<el-button type="primary">新增</el-button>
<el-button type="danger">删除</el-button>
<el-button type="success">保存</el-button>
<el-button type="primary" link>编辑</el-button> <!-- link 类型:文字按钮 -->
常用 type 值:
| type | 用途 |
|---|---|
| primary | 主要操作(蓝) |
| success | 成功(绿) |
| warning | 警告(橙) |
| danger | 危险(红) |
| info | 信息(灰) |
4.2 表格(el-table)
表格是后台系统最常用的组件,用于展示列表数据:
html
<el-table :data="list" border stripe>
<el-table-column label="ID" prop="id" width="80"></el-table-column>
<el-table-column label="姓名" prop="name" width="150"></el-table-column>
<el-table-column label="籍贯" prop="place"></el-table-column>
<el-table-column label="操作" width="150">
<template #default="{ row }">
<el-button type="primary" link @click="handleEdit(row)">编辑</el-button>
<el-button type="danger" link @click="handleDelete(row.id)">删除</el-button>
</template>
</el-table-column>
</el-table>
关键属性说明:
| 属性 | 作用 |
|---|---|
:data |
绑定数据源(数组) |
border |
显示边框 |
stripe |
斑马纹效果 |
prop |
对应数据中的字段名 |
#default |
作用域插槽,{ row } 可以获取当前行数据 |
4.3 表单(el-form)
表单用于数据输入,配合弹窗使用非常常见:
html
<el-form label-width="50px">
<el-form-item label="姓名">
<el-input v-model="formData.name" placeholder="请输入姓名" />
</el-form-item>
<el-form-item label="籍贯">
<el-input v-model="formData.place" placeholder="请输入籍贯" />
</el-form-item>
</el-form>
4.4 弹窗(el-dialog)
弹窗常用于新增/编辑操作:
html
<el-dialog v-model="dialogVisible" title="编辑" width="400px">
<!-- 弹窗内容 -->
<el-form>...</el-form>
<!-- 底部按钮插槽 -->
<template #footer>
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="handleSave">确认</el-button>
</template>
</el-dialog>
核心要点:
v-model控制弹窗的显示/隐藏#footer插槽用于自定义底部按钮
4.5 分页(el-pagination)
当数据量大时,需要分页展示:
html
<el-pagination
background
layout="prev, pager, next"
:total="list.length"
:current-page="currentPage"
:page-size="pageSize"
@current-change="handlePageChange"
/>
关键属性:
| 属性 | 作用 |
|---|---|
:total |
数据总条数 |
:current-page |
当前页码(从 1 开始) |
:page-size |
每页显示条数 |
@current-change |
页码改变时触发的事件 |
background |
按钮显示背景色 |
layout |
布局组件,逗号分隔 |
常用 layout 值:
prev 上一页按钮
pager 页码列表
next 下一页按钮
total 显示总条数
sizes 每页条数选择器
jumper 跳转到指定页
五、完整项目示例
下面是一个包含 列表展示、删除、编辑、分页 的完整示例:
5.1 项目结构
src/
├── App.vue ← 主页面
├── main.js ← 入口文件
└── components/
└── Edit.vue ← 编辑弹窗组件
5.2 main.js --- 入口文件
js
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')
5.3 App.vue --- 主页面
html
<script setup>
import { ref, computed } from 'vue'
import Edit from './components/Edit.vue'
// 列表数据
const list = ref([
{ id: 1, name: '张三', place: '北京' },
{ id: 2, name: '李四', place: '上海' },
{ id: 3, name: '王五', place: '广州' },
{ id: 4, name: '赵六', place: '深圳' },
{ id: 5, name: '孙七', place: '杭州' },
{ id: 6, name: '周八', place: '成都' },
{ id: 7, name: '吴九', place: '武汉' },
{ id: 8, name: '郑十', place: '南京' },
{ id: 9, name: '陈十一', place: '西安' },
{ id: 10, name: '林十二', place: '重庆' }
])
// ========== 分页相关 ==========
const currentPage = ref(1)
const pageSize = ref(5)
// 计算当前页显示的数据
const pageData = computed(() => {
const start = (currentPage.value - 1) * pageSize.value
const end = start + pageSize.value
return list.value.slice(start, end)
})
const handlePageChange = (page) => {
currentPage.value = page
}
// ========== 删除功能 ==========
const handleDelete = (id) => {
const index = list.value.findIndex(item => item.id === id)
if (index !== -1) {
list.value.splice(index, 1)
}
}
// ========== 编辑功能 ==========
const editRef = ref(null)
const handleEdit = (row) => {
editRef.value.open({ ...row })
}
const handleSave = (formData) => {
const index = list.value.findIndex(item => item.id === formData.id)
if (index !== -1) {
list.value[index] = { ...formData }
}
}
</script>
<template>
<div class="app">
<el-table :data="pageData" border stripe>
<el-table-column label="ID" prop="id" width="80"></el-table-column>
<el-table-column label="姓名" prop="name" width="150"></el-table-column>
<el-table-column label="籍贯" prop="place"></el-table-column>
<el-table-column label="操作" width="150">
<template #default="{ row }">
<el-button type="primary" link @click="handleEdit(row)">编辑</el-button>
<el-button type="danger" link @click="handleDelete(row.id)">删除</el-button>
</template>
</el-table-column>
</el-table>
<el-pagination
background
layout="prev, pager, next"
:total="list.length"
:current-page="currentPage"
:page-size="pageSize"
@current-change="handlePageChange"
/>
</div>
<Edit ref="editRef" @save="handleSave" />
</template>
<style scoped>
.app {
width: 980px;
margin: 100px auto 0;
}
</style>
5.4 Edit.vue --- 编辑弹窗子组件
html
<script setup>
import { ref, defineExpose, defineEmits } from 'vue'
const emit = defineEmits(['save'])
// 弹窗开关
const dialogVisible = ref(false)
// 表单数据
const formData = ref({ id: '', name: '', place: '' })
// 打开弹窗(供父组件调用)
const open = (row) => {
formData.value = { ...row }
dialogVisible.value = true
}
// 保存
const handleSave = () => {
emit('save', formData.value)
dialogVisible.value = false
}
// 暴露 open 方法给父组件
defineExpose({ open })
</script>
<template>
<el-dialog v-model="dialogVisible" title="编辑" width="400px">
<el-form label-width="50px">
<el-form-item label="姓名">
<el-input v-model="formData.name" placeholder="请输入姓名" />
</el-form-item>
<el-form-item label="籍贯">
<el-input v-model="formData.place" placeholder="请输入籍贯" />
</el-form-item>
</el-form>
<template #footer>
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="handleSave">确认</el-button>
</template>
</el-dialog>
</template>
<style scoped>
.el-input {
width: 290px;
}
</style>
六、父子组件通信要点
这个项目中涉及几个关键的父子组件通信方式,值得理解:
父调子:defineExpose + ref
js
// 子组件:暴露方法
defineExpose({ open })
// 父组件:通过 ref 调用
const editRef = ref(null)
editRef.value.open(data) // 调用子组件的 open 方法
子传父:defineEmits + emit
js
// 子组件:声明并发射事件
const emit = defineEmits(['save'])
emit('save', formData)
// 父组件:监听事件
<Edit @save="handleSave" />
七、分页逻辑详解
分页的核心就是用 computed 计算当前页的数据:
当前页数据 = list.slice((页码 - 1) * 每页条数, 页码 * 每页条数)
以 pageSize = 5 为例:
| 页码 | 截取范围 | 显示数据 |
|---|---|---|
| 1 | 0 ~ 5 | 第1 ~ 第5条 |
| 2 | 5 ~ 10 | 第6 ~ 第10条 |
| 3 | 10 ~ 15 | 第11 ~ 第15条 |
八、常见问题
Q1:引入后样式没有生效?
忘记引入 import 'element-plus/dist/index.css',这是最常见的问题。
Q2:组件没有显示?
确认 main.js 中有 app.use(ElementPlus),否则组件不会被注册。
Q3:表格数据不更新?
确保绑定的数据是响应式的(使用 ref 或 reactive),不要直接操作非响应式数据。
Q4:弹窗打不开?
检查 v-model="dialogVisible" 中的变量是否是 ref,且模板中访问的是 dialogVisible 而不是 dialogVisible.value(模板中会自动解包)。
总结
| 步骤 | 操作 |
|---|---|
| 1️⃣ | npm install element-plus |
| 2️⃣ | main.js 中 import ElementPlus + app.use(ElementPlus) |
| 3️⃣ | 组件中直接使用 <el-xxx> 标签 |
| 4️⃣ | 数据用 ref 管理,保证响应式 |
Element Plus 的官方文档 https://element-plus.org/zh-CN/ 有每个组件的完整 API,遇到不确定的属性可以随时查阅。