0
0

Element Plus 笔记

2026-02-26
2026-07-23

element plus可以先当做html看

基本可以 先当成 HTML 看,但要补一句:Element Plus 是“带功能的 HTML 标签”,不是普通标签。

你可以这样理解:

<el-button type="primary" @click="submit">提交</el-button>

就当成:

<button onclick="submit()">提交</button>

只不过 Element Plus 帮你额外做好了:

样式:按钮颜色、大小、禁用、loading
交互:点击、弹窗、表单校验、表格选择
数据绑定:和 Vue 的 v-model / :data / @click 配合

所以你看项目时,不用一开始纠结 Element Plus 原理。先按 HTML 结构读页面就行:

<el-form>
  <el-form-item>
    <el-input />
  </el-form-item>
</el-form>

你就当成:

<form>
  <div>
    <input />
  </div>
</form>
<el-table :data="userList">
  <el-table-column prop="username" label="用户名" />
</el-table>

你就当成:

<table>
  <tr>
    <td>用户名</td>
  </tr>
</table>

但有几个地方必须知道,不然看不懂项目。


1. el-xxx 是组件,不是原生 HTML

<el-input v-model="form.username" />

不是浏览器原生标签,而是 Element Plus 封装的 Vue 组件。

但是你可以把它理解成:

<input />

核心看这几个东西:

v-model="form.username"

意思是:输入框的值绑定到 form.username


2. el-form 就是表单容器

<el-form :model="form">
  <el-form-item label="用户名">
    <el-input v-model="form.username" />
  </el-form-item>
</el-form>

你可以当成:

<form>
  <label>用户名</label>
  <input />
</form>

真正要看懂的是:

:model="form"
v-model="form.username"

也就是这个页面的数据来自 form


3. el-table 就是表格

<el-table :data="userList">
  <el-table-column prop="id" label="ID" />
  <el-table-column prop="username" label="用户名" />
</el-table>

你可以当成:

<table>
  <tr>
    <th>ID</th>
    <th>用户名</th>
  </tr>
</table>

真正要看懂的是:

:data="userList"
prop="username"

意思是:

userList 是表格数据
prop="username" 表示这一列显示每一行的 username 字段

如果数据是:

[
  { id: 1, username: 'admin' },
  { id: 2, username: 'tom' }
]

页面就会显示两行。


4. el-dialog 就是弹窗

<el-dialog v-model="dialogVisible" title="新增用户">
  ...
</el-dialog>

你可以当成:

<div class="弹窗">
  ...
</div>

关键是:

v-model="dialogVisible"

意思是:

dialogVisible = true  弹窗显示
dialogVisible = false 弹窗隐藏

5. @click 就是点击事件

<el-button @click="handleAdd">新增</el-button>

就当成:

<button onclick="handleAdd()">新增</button>

然后你去 JS 里找:

const handleAdd = () => {
  dialogVisible.value = true
}

这就说明:点击新增,打开弹窗。


你看项目时就按这个顺序

不要先研究 Element Plus 文档,先这样读:

1. 看页面有哪些块:查询区、表格区、分页区、弹窗区
2. 看按钮 @click 绑定了哪个方法
3. 去 script 里找这个方法
4. 看方法里调了哪个接口
5. 看接口返回的数据赋值给了谁
6. 回到 template 看这个数据被哪个组件使用

比如:

<el-button @click="getList">查询</el-button>
<el-table :data="userList" />

你就知道:

点击查询 → 执行 getList → 请求后端 → 结果放进 userList → 表格显示 userList

最简理解

可以先这样记:

el-button      ≈ button
el-input       ≈ input
el-select      ≈ select
el-form        ≈ form
el-form-item   ≈ 表单一行
el-table       ≈ table
el-table-column≈ 表格一列
el-dialog      ≈ 弹窗 div
el-pagination  ≈ 分页按钮组

但是重点不是 Element Plus 标签本身,而是标签上的这些东西:

v-model  数据绑定
:data    数据来源
prop     显示哪个字段
@click   点击执行哪个方法
v-if     是否显示
v-for    循环渲染

所以结论是:对,你可以先把 Element Plus 当成增强版 HTML 看。真正要学的是 Vue 的数据绑定、事件、接口请求和页面流程。

1. Element Plus 是什么

Element Plus 是 Vue3 的 UI 组件库。它已经帮你写好了后台管理系统常用的按钮、输入框、表单、表格、分页、弹窗、上传、菜单等组件。

普通 HTML 写按钮:

<button>提交</button> <!-- 原生按钮,需要自己写样式和交互 -->

Element Plus 写按钮:

<el-button type="primary">提交</el-button> <!-- Element Plus 按钮,自带样式和交互 -->

它的作用可以简单理解为:

Vue 负责数据和逻辑
Element Plus 负责页面组件和样式
你负责把数据、事件、接口接起来

后台项目最常用的组件:

el-button        按钮
el-input         输入框
el-select        下拉框
el-form          表单
el-form-item     表单项
el-table         表格
el-table-column  表格列
el-pagination    分页
el-dialog        弹窗
el-upload        上传
ElMessage        消息提示
ElMessageBox     确认框

2. 安装和注册

安装:

npm install element-plus # 安装 Element Plus 组件库

main.tsmain.js 里注册:

import { createApp } from 'vue' // 从 vue 中导入创建应用的方法
import ElementPlus from 'element-plus' // 导入 Element Plus 组件库
import 'element-plus/dist/index.css' // 导入 Element Plus 默认样式
import App from './App.vue' // 导入根组件 App

const app = createApp(App) // 创建 Vue 应用实例

app.use(ElementPlus) // 把 Element Plus 注册到 Vue 应用中

app.mount('#app') // 把 Vue 应用挂载到 id 为 app 的 DOM 上

注册之后,项目里就可以直接写:

<el-button>按钮</el-button> <!-- 使用 Element Plus 按钮组件 -->
<el-input /> <!-- 使用 Element Plus 输入框组件 -->
<el-table /> <!-- 使用 Element Plus 表格组件 -->

有些项目看不到 app.use(ElementPlus),可能是用了自动按需导入。那就去看:

main.ts        看有没有全局注册
vite.config.ts 看有没有自动导入插件

3. Element Plus 的核心使用规律

Element Plus 组件本质还是 Vue 组件,所以核心规则还是 Vue 那一套:

<el-button type="primary" :loading="loading" @click="submit">
  提交
</el-button>

解释:

el-button:组件名
type="primary":静态属性,表示主要按钮
:loading="loading":动态属性,loading 为 true 时按钮转圈
@click="submit":点击按钮时执行 submit 方法
提交:按钮显示的文字

Vue 中最常见的几个符号:

v-model  双向绑定数据
:xxx     动态绑定属性,等价于 v-bind:xxx
@xxx     绑定事件,等价于 v-on:xxx
v-for    循环渲染
v-if     条件渲染
ref      获取组件实例,调用组件方法
slot     插槽,自定义组件内部内容

4. Button 按钮

4.1 基础按钮

<el-button>默认按钮</el-button> <!-- 默认样式按钮 -->
<el-button type="primary">主要按钮</el-button> <!-- 蓝色主按钮,常用于提交、查询、新增 -->
<el-button type="success">成功按钮</el-button> <!-- 绿色按钮,常用于成功状态 -->
<el-button type="warning">警告按钮</el-button> <!-- 黄色按钮,常用于警告操作 -->
<el-button type="danger">危险按钮</el-button> <!-- 红色按钮,常用于删除等危险操作 -->

4.2 按钮绑定事件

<el-button type="primary" @click="handleSearch">查询</el-button> <!-- 点击后执行 handleSearch 方法 -->
<el-button @click="handleReset">重置</el-button> <!-- 点击后执行 handleReset 方法 -->
<el-button type="primary" @click="handleAdd">新增</el-button> <!-- 点击后执行 handleAdd 方法 -->
<el-button type="danger" @click="handleDelete(row.id)">删除</el-button> <!-- 点击后把当前行 id 传给删除方法 -->

对应 JS:

const handleSearch = () => { // 定义查询方法
  query.page = 1 // 查询时把页码重置为第 1 页
  getList() // 重新请求列表数据
}

const handleReset = () => { // 定义重置方法
  query.keyword = '' // 清空关键词
  query.page = 1 // 页码重置为第 1 页
  getList() // 重新请求列表
}

const handleAdd = () => { // 定义新增方法
  dialogVisible.value = true // 打开弹窗
}

按钮的核心作用:触发业务方法,比如查询、重置、新增、编辑、删除、提交。


5. Input 输入框

5.1 基础输入框

<el-input v-model="username" placeholder="请输入用户名" /> <!-- 输入框内容和 username 双向绑定 -->

对应 JS:

import { ref } from 'vue' // 导入 ref,用于定义响应式数据

const username = ref('') // 定义 username,初始值为空字符串

理解:

用户在输入框输入内容
username 的值会自动变化
username 变化,输入框内容也会自动变化

5.2 表单对象中的输入框

实际项目更常用这种:

<el-input v-model="form.username" placeholder="请输入用户名" /> <!-- 输入内容绑定到 form.username -->
<el-input v-model="form.password" type="password" placeholder="请输入密码" /> <!-- 输入内容绑定到 form.password,并且是密码框 -->

对应 JS:

import { reactive } from 'vue' // 导入 reactive,用于定义响应式对象

const form = reactive({ // 定义表单对象
  username: '', // 用户名字段,初始为空
  password: '' // 密码字段,初始为空
})

5.3 常用属性

<el-input v-model="keyword" clearable placeholder="请输入关键词" /> <!-- clearable 表示输入框右侧有清空按钮 -->
<el-input v-model="password" show-password type="password" /> <!-- show-password 表示可以点击图标显示或隐藏密码 -->
<el-input v-model="content" type="textarea" placeholder="请输入内容" /> <!-- type 为 textarea 表示多行文本框 -->

6. Form 表单

6.1 表单的作用

el-form 用来管理一组输入项,常用于:

登录表单
新增表单
编辑表单
搜索表单
提交审核表单

结构固定是:

el-form 包住整个表单
el-form-item 表示一行表单项
el-input / el-select 等放在 el-form-item 里面

6.2 基础表单

<el-form :model="form" label-width="100px"> <!-- el-form 表示整个表单,model 指定表单数据对象 -->
  <el-form-item label="用户名"> <!-- el-form-item 表示一个表单项,label 是左侧文字 -->
    <el-input v-model="form.username" /> <!-- 输入框绑定 form.username -->
  </el-form-item> <!-- 用户名表单项结束 -->

  <el-form-item label="密码"> <!-- 第二个表单项,左侧显示密码 -->
    <el-input v-model="form.password" type="password" /> <!-- 输入框绑定 form.password,并设置为密码框 -->
  </el-form-item> <!-- 密码表单项结束 -->

  <el-form-item> <!-- 按钮区域,也可以放在表单项里 -->
    <el-button type="primary" @click="submit">提交</el-button> <!-- 点击后执行 submit 方法 -->
  </el-form-item> <!-- 按钮表单项结束 -->
</el-form> <!-- 表单结束 -->

对应 JS:

import { reactive } from 'vue' // 导入 reactive

const form = reactive({ // 定义表单数据对象
  username: '', // 用户名字段
  password: '' // 密码字段
})

const submit = () => { // 定义提交方法
  console.log(form) // 打印整个表单对象
}

7. Form 表单校验

7.1 校验的作用

表单校验就是在提交前检查数据是否合法,比如:

用户名不能为空
密码至少 6 位
手机号格式正确
邮箱格式正确
必须选择角色

7.2 基础校验写法

<el-form ref="formRef" :model="form" :rules="rules" label-width="100px"> <!-- ref 用来拿到表单实例,model 绑定数据,rules 绑定校验规则 -->
  <el-form-item label="用户名" prop="username"> <!-- prop 必须对应 form.username 和 rules.username -->
    <el-input v-model="form.username" /> <!-- 输入框绑定用户名 -->
  </el-form-item> <!-- 用户名表单项结束 -->

  <el-form-item label="密码" prop="password"> <!-- prop 必须对应 form.password 和 rules.password -->
    <el-input v-model="form.password" type="password" show-password /> <!-- 输入框绑定密码,并支持显示隐藏密码 -->
  </el-form-item> <!-- 密码表单项结束 -->

  <el-form-item> <!-- 按钮表单项 -->
    <el-button type="primary" @click="submit">提交</el-button> <!-- 点击后提交表单 -->
  </el-form-item> <!-- 按钮表单项结束 -->
</el-form> <!-- 表单结束 -->

对应 JS:

import { reactive, ref } from 'vue' // 导入 reactive 和 ref

const formRef = ref() // 用来保存 el-form 组件实例

const form = reactive({ // 定义表单数据
  username: '', // 用户名字段
  password: '' // 密码字段
})

const rules = { // 定义校验规则
  username: [ // username 字段的校验规则
    { required: true, message: '请输入用户名', trigger: 'blur' } // 必填,失去焦点时校验
  ], // username 校验结束
  password: [ // password 字段的校验规则
    { required: true, message: '请输入密码', trigger: 'blur' }, // 必填,失去焦点时校验
    { min: 6, message: '密码至少 6 位', trigger: 'blur' } // 最少 6 位,失去焦点时校验
  ] // password 校验结束
}

const submit = async () => { // 定义提交方法,因为 validate 是异步的,所以用 async
  await formRef.value.validate() // 调用 el-form 的 validate 方法,校验整个表单
  console.log('校验通过,可以调接口') // 校验通过后才会执行到这里
}

最重要的对应关系:

form.username // 表单数据字段
rules.username // 校验规则字段
prop="username" // 表单项绑定字段

这三个必须一致,不然校验不会生效。


8. Select 下拉框

8.1 基础用法

<el-select v-model="form.status" placeholder="请选择状态"> <!-- 下拉框绑定 form.status -->
  <el-option label="启用" :value="1" /> <!-- 页面显示启用,实际值是数字 1 -->
  <el-option label="禁用" :value="0" /> <!-- 页面显示禁用,实际值是数字 0 -->
</el-select> <!-- 下拉框结束 -->

对应 JS:

const form = reactive({ // 定义表单对象
  status: null // 状态字段,初始为空
})

理解:

页面显示:启用 / 禁用
实际保存:1 / 0
提交给后端:form.status

8.2 动态选项

后端返回角色列表时,常这样写:

<el-select v-model="form.roleId" placeholder="请选择角色"> <!-- 下拉框绑定 form.roleId -->
  <el-option
    v-for="item in roleOptions"
    :key="item.id"
    :label="item.name"
    :value="item.id"
  /> <!-- 循环生成选项,显示角色名,实际保存角色 id -->
</el-select> <!-- 下拉框结束 -->

对应 JS:

const roleOptions = ref([ // 定义角色选项列表
  { id: 1, name: '管理员' }, // 第一个选项
  { id: 2, name: '普通用户' } // 第二个选项
])

注意:

<el-option label="启用" :value="1" /> <!-- 数字 1 -->
<el-option label="启用" value="1" /> <!-- 字符串 "1" -->

后端要数字,就用 :value="1"


9. Table 表格

9.1 表格作用

el-table 用来展示列表数据,比如:

用户列表
订单列表
文件列表
角色列表
商品列表

核心结构:

el-table:整个表格
:data:表格数据
el-table-column:表格中的一列
prop:读取当前行的哪个字段
label:表头显示什么

9.2 基础表格

<el-table :data="userList" border> <!-- 表格绑定 userList 数据,border 表示显示边框 -->
  <el-table-column prop="id" label="ID" width="80" /> <!-- 显示每行的 id 字段,表头叫 ID,宽度 80 -->
  <el-table-column prop="username" label="用户名" /> <!-- 显示每行的 username 字段,表头叫用户名 -->
  <el-table-column prop="email" label="邮箱" /> <!-- 显示每行的 email 字段,表头叫邮箱 -->
</el-table> <!-- 表格结束 -->

对应 JS:

const userList = ref([ // 定义表格数据列表
  { id: 1, username: 'admin', email: '[已隐藏邮箱]' }, // 第一行数据
  { id: 2, username: 'tom', email: '[已隐藏邮箱]' } // 第二行数据
])

理解:

userList 有几条数据,表格就有几行
el-table-column 有几列,表格就显示几列
prop="username",表示这一列显示 row.username

10. Table 自定义列

10.1 为什么需要自定义列

后端可能返回:

status: 1

但是页面不能直接显示 1,而是显示:

启用

这时就用插槽自定义显示内容。

10.2 状态列

<el-table-column label="状态"> <!-- 定义状态列,表头显示状态 -->
  <template #default="{ row }"> <!-- 获取当前行数据 row -->
    <el-tag :type="row.status === 1 ? 'success' : 'danger'"> <!-- 根据状态决定标签颜色 -->
      {{ row.status === 1 ? '启用' : '禁用' }} <!-- 根据状态显示启用或禁用 -->
    </el-tag> <!-- 标签结束 -->
  </template> <!-- 插槽结束 -->
</el-table-column> <!-- 状态列结束 -->

这里的 row 就是当前行数据。

假设当前行是:

const row = { // 当前行数据
  id: 1, // 用户 id
  username: 'admin', // 用户名
  status: 1 // 用户状态
}

那么:

row.id // 取当前行 id
row.username // 取当前行用户名
row.status // 取当前行状态

10.3 操作列

<el-table-column label="操作" width="180"> <!-- 定义操作列,宽度 180 -->
  <template #default="{ row }"> <!-- 获取当前行数据 row -->
    <el-button size="small" @click="handleEdit(row)">编辑</el-button> <!-- 点击编辑,把当前行传给 handleEdit -->
    <el-button size="small" type="danger" @click="handleDelete(row.id)">删除</el-button> <!-- 点击删除,把当前行 id 传给 handleDelete -->
  </template> <!-- 插槽结束 -->
</el-table-column> <!-- 操作列结束 -->

这是后台项目里最常见的代码。


11. Pagination 分页

11.1 分页作用

分页是为了不要一次性查出全部数据,而是按页查询。

常见后端参数:

page 当前页
size 每页条数
keyword 搜索关键词

11.2 分页组件

<el-pagination
  v-model:current-page="query.page"
  v-model:page-size="query.size"
  :total="total"
  :page-sizes="[10, 20, 50, 100]"
  layout="total, sizes, prev, pager, next, jumper"
  @current-change="getList"
  @size-change="getList"
/> <!-- 分页组件结束 -->

上面多行属性解释:

v-model:current-page="query.page":当前页绑定 query.page
v-model:page-size="query.size":每页条数绑定 query.size
:total="total":总数据条数
:page-sizes="[10,20,50,100]":可以选择每页 10 / 20 / 50 / 100 条
layout:控制分页显示哪些部分
@current-change="getList":页码变化时重新请求列表
@size-change="getList":每页条数变化时重新请求列表

对应 JS:

const query = reactive({ // 定义查询参数对象
  keyword: '', // 搜索关键词
  page: 1, // 当前页,默认第 1 页
  size: 10 // 每页条数,默认 10 条
})

const total = ref(0) // 总条数,后端返回后赋值

列表请求:

const getList = async () => { // 定义获取列表方法
  const res = await getUserListApi(query) // 调用后端接口,把 query 作为查询参数传过去
  userList.value = res.data.records // 把后端返回的当前页数据赋值给表格
  total.value = res.data.total // 把后端返回的总条数赋值给分页组件
}

搜索时要重置页码:

const handleSearch = () => { // 定义搜索方法
  query.page = 1 // 搜索新条件时,必须回到第 1 页
  getList() // 重新请求列表
}

12. Dialog 弹窗

12.1 弹窗作用

el-dialog 常用于:

新增用户
编辑用户
查看详情
修改密码
上传文件

它通常和表单一起使用。

12.2 基础弹窗

<el-dialog v-model="dialogVisible" title="新增用户" width="500px"> <!-- 弹窗显示状态绑定 dialogVisible,标题是新增用户,宽度 500px -->
  <el-form :model="form" label-width="100px"> <!-- 弹窗内部放表单,绑定 form 数据 -->
    <el-form-item label="用户名"> <!-- 用户名表单项 -->
      <el-input v-model="form.username" /> <!-- 输入框绑定 form.username -->
    </el-form-item> <!-- 用户名表单项结束 -->
  </el-form> <!-- 表单结束 -->

  <template #footer> <!-- 自定义弹窗底部区域 -->
    <el-button @click="dialogVisible = false">取消</el-button> <!-- 点击取消,关闭弹窗 -->
    <el-button type="primary" @click="submit">确定</el-button> <!-- 点击确定,执行 submit 方法 -->
  </template> <!-- 底部区域结束 -->
</el-dialog> <!-- 弹窗结束 -->

对应 JS:

const dialogVisible = ref(false) // 控制弹窗是否显示,false 表示不显示

const form = reactive({ // 定义弹窗表单数据
  id: null, // id 为空表示新增,有值表示编辑
  username: '' // 用户名字段
})

12.3 新增打开弹窗

const handleAdd = () => { // 定义新增方法
  form.id = null // 新增时没有 id
  form.username = '' // 清空用户名
  dialogVisible.value = true // 打开弹窗
}

12.4 编辑打开弹窗

const handleEdit = (row) => { // 定义编辑方法,row 是当前行数据
  form.id = row.id // 把当前行 id 回填到表单
  form.username = row.username // 把当前行用户名回填到表单
  dialogVisible.value = true // 打开弹窗
}

12.5 新增和编辑共用提交

const submit = async () => { // 定义提交方法
  if (form.id) { // 如果 form.id 有值,说明是编辑
    await updateUserApi(form) // 调用编辑接口
    ElMessage.success('修改成功') // 显示修改成功提示
  } else { // 如果 form.id 没有值,说明是新增
    await addUserApi(form) // 调用新增接口
    ElMessage.success('新增成功') // 显示新增成功提示
  }

  dialogVisible.value = false // 提交成功后关闭弹窗
  getList() // 重新请求列表,刷新表格
}

13. Message 消息提示

13.1 作用

ElMessage 用来显示操作结果,比如:

保存成功
删除成功
操作失败
请选择数据

13.2 用法

import { ElMessage } from 'element-plus' // 导入消息提示 API

ElMessage.success('保存成功') // 成功提示
ElMessage.error('保存失败') // 错误提示
ElMessage.warning('请选择数据') // 警告提示
ElMessage.info('已取消操作') // 普通提示

实际项目中:

const handleSave = async () => { // 定义保存方法
  await saveUserApi(form) // 调用保存接口
  ElMessage.success('保存成功') // 接口成功后提示保存成功
  getList() // 重新刷新列表
}

14. MessageBox 确认框

14.1 作用

删除、退出登录、清空数据这种危险操作,不能直接执行,要先让用户确认。

14.2 删除确认

import { ElMessage, ElMessageBox } from 'element-plus' // 导入消息提示和确认框

const handleDelete = async (id) => { // 定义删除方法,参数 id 是要删除的数据 id
  await ElMessageBox.confirm('确定要删除这条数据吗?', '提示', { // 弹出确认框,等待用户点击确定
    type: 'warning', // 确认框类型为警告
    confirmButtonText: '确定', // 确定按钮文字
    cancelButtonText: '取消' // 取消按钮文字
  }) // 确认框配置结束

  await deleteUserApi(id) // 用户点击确定后,调用删除接口
  ElMessage.success('删除成功') // 删除成功后显示提示
  getList() // 刷新列表
}

理解:

用户点确定:confirm 成功,继续往下执行
用户点取消:confirm 报错,后面的删除接口不会执行

15. Upload 上传

15.1 上传作用

el-upload 用来上传文件,比如:

上传头像
上传图片
上传附件
上传 Excel
上传网盘文件

15.2 基础上传

<el-upload
  action="/api/files/upload"
  :headers="headers"
  :on-success="handleUploadSuccess"
  :before-upload="beforeUpload"
>
  <el-button type="primary">点击上传</el-button> <!-- 上传按钮 -->
</el-upload> <!-- 上传组件结束 -->

属性解释:

action:上传接口地址
headers:上传请求头,常用来带 token
on-success:上传成功后的回调函数
before-upload:上传前的校验函数

对应 JS:

const headers = { // 定义上传请求头
  Authorization: `Bearer ${localStorage.getItem('token')}` // 从本地存储取 token,放到请求头
}

const beforeUpload = (file) => { // 上传前执行,file 是当前上传的文件
  const isLt2M = file.size / 1024 / 1024 < 2 // 判断文件大小是否小于 2MB

  if (!isLt2M) { // 如果文件大于等于 2MB
    ElMessage.error('文件大小不能超过 2MB') // 显示错误提示
  }

  return isLt2M // 返回 true 才允许上传,返回 false 会阻止上传
}

const handleUploadSuccess = (res) => { // 上传成功后执行,res 是后端返回结果
  form.fileUrl = res.data.url // 把后端返回的文件地址保存到表单里
}

注意:上传文件一般不是普通 JSON 请求,而是 multipart/form-data


16. 后台列表页完整流程

一个后台管理页面通常长这样:

查询条件
表格
分页
新增弹窗
编辑回填
删除确认
接口请求
成功提示

核心流程:

页面加载 → getList 请求列表
查询按钮 → 修改 query → getList
分页变化 → 修改 page/size → getList
新增按钮 → 清空 form → 打开 dialog
编辑按钮 → row 回填 form → 打开 dialog
确定按钮 → 校验 form → add/update 接口 → 关闭弹窗 → getList
删除按钮 → confirm 确认 → delete 接口 → getList

17. 一个最常用的完整模板

这个模板是后台页面的骨架,理解它基本就能看懂大部分 Element Plus 页面。

<script setup lang="ts"> <!-- Vue3 setup 语法,写页面逻辑 -->
import { reactive, ref, onMounted } from 'vue' // 导入 Vue 响应式和生命周期方法
import { ElMessage, ElMessageBox } from 'element-plus' // 导入消息提示和确认框
import { getUserListApi, addUserApi, updateUserApi, deleteUserApi } from '@/api/user' // 导入用户相关接口

const loading = ref(false) // 表格加载状态
const dialogVisible = ref(false) // 弹窗显示状态
const formRef = ref() // 表单实例,用于调用 validate 校验方法

const query = reactive({ // 查询参数对象
  keyword: '', // 搜索关键词
  status: null, // 状态筛选
  page: 1, // 当前页
  size: 10 // 每页条数
})

const total = ref(0) // 总数据条数
const userList = ref([]) // 表格数据列表

const form = reactive({ // 新增和编辑共用的表单数据
  id: null, // id 为空表示新增,有值表示编辑
  username: '', // 用户名
  status: 1 // 用户状态,默认启用
})

const rules = { // 表单校验规则
  username: [ // 用户名字段规则
    { required: true, message: '请输入用户名', trigger: 'blur' } // 用户名必填,失去焦点时校验
  ] // 用户名规则结束
}

const getList = async () => { // 获取用户列表
  loading.value = true // 开启表格加载状态

  try { // 使用 try finally 保证 loading 最后会关闭
    const res = await getUserListApi(query) // 调用列表接口,把 query 作为参数传给后端
    userList.value = res.data.records // 把当前页数据赋值给表格
    total.value = res.data.total // 把总条数赋值给分页
  } finally { // 无论接口成功还是失败都会执行
    loading.value = false // 关闭表格加载状态
  }
}

const handleSearch = () => { // 查询方法
  query.page = 1 // 查询新条件时回到第 1 页
  getList() // 重新请求列表
}

const handleReset = () => { // 重置方法
  query.keyword = '' // 清空关键词
  query.status = null // 清空状态
  query.page = 1 // 回到第 1 页
  getList() // 重新请求列表
}

const handleAdd = () => { // 新增方法
  form.id = null // 新增时 id 为空
  form.username = '' // 清空用户名
  form.status = 1 // 默认启用
  dialogVisible.value = true // 打开弹窗
}

const handleEdit = (row) => { // 编辑方法,row 是当前行数据
  form.id = row.id // 回填 id
  form.username = row.username // 回填用户名
  form.status = row.status // 回填状态
  dialogVisible.value = true // 打开弹窗
}

const handleSubmit = async () => { // 提交方法
  await formRef.value.validate() // 先校验表单,校验失败会停止后续代码

  if (form.id) { // 有 id 表示编辑
    await updateUserApi(form) // 调用编辑接口
    ElMessage.success('修改成功') // 提示修改成功
  } else { // 没有 id 表示新增
    await addUserApi(form) // 调用新增接口
    ElMessage.success('新增成功') // 提示新增成功
  }

  dialogVisible.value = false // 关闭弹窗
  getList() // 刷新列表
}

const handleDelete = async (id) => { // 删除方法
  await ElMessageBox.confirm('确定删除该用户吗?', '提示', { type: 'warning' }) // 删除前弹出确认框
  await deleteUserApi(id) // 用户点确定后调用删除接口
  ElMessage.success('删除成功') // 提示删除成功
  getList() // 刷新列表
}

onMounted(() => { // 页面挂载完成后执行
  getList() // 页面一进来就请求列表
})
</script> <!-- 脚本结束 -->

<template> <!-- 页面模板开始 -->
  <div class="user-page"> <!-- 页面最外层容器 -->
    <el-form :inline="true" :model="query"> <!-- 查询表单,inline 表示一行显示 -->
      <el-form-item label="关键词"> <!-- 关键词表单项 -->
        <el-input v-model="query.keyword" clearable placeholder="请输入用户名" /> <!-- 输入框绑定 query.keyword -->
      </el-form-item> <!-- 关键词表单项结束 -->

      <el-form-item label="状态"> <!-- 状态表单项 -->
        <el-select v-model="query.status" clearable placeholder="请选择状态" style="width: 160px"> <!-- 下拉框绑定 query.status -->
          <el-option label="启用" :value="1" /> <!-- 启用选项,实际值为数字 1 -->
          <el-option label="禁用" :value="0" /> <!-- 禁用选项,实际值为数字 0 -->
        </el-select> <!-- 下拉框结束 -->
      </el-form-item> <!-- 状态表单项结束 -->

      <el-form-item> <!-- 按钮区域 -->
        <el-button type="primary" @click="handleSearch">查询</el-button> <!-- 点击查询 -->
        <el-button @click="handleReset">重置</el-button> <!-- 点击重置 -->
        <el-button type="primary" @click="handleAdd">新增</el-button> <!-- 点击新增 -->
      </el-form-item> <!-- 按钮区域结束 -->
    </el-form> <!-- 查询表单结束 -->

    <el-table :data="userList" border v-loading="loading"> <!-- 表格绑定 userList,loading 为 true 时显示加载状态 -->
      <el-table-column prop="id" label="ID" width="80" /> <!-- ID 列 -->
      <el-table-column prop="username" label="用户名" /> <!-- 用户名列 -->

      <el-table-column label="状态"> <!-- 状态列 -->
        <template #default="{ row }"> <!-- 获取当前行 row -->
          <el-tag :type="row.status === 1 ? 'success' : 'danger'"> <!-- 根据状态设置标签颜色 -->
            {{ row.status === 1 ? '启用' : '禁用' }} <!-- 根据状态显示文字 -->
          </el-tag> <!-- 标签结束 -->
        </template> <!-- 状态列插槽结束 -->
      </el-table-column> <!-- 状态列结束 -->

      <el-table-column label="操作" width="180"> <!-- 操作列 -->
        <template #default="{ row }"> <!-- 获取当前行 row -->
          <el-button size="small" @click="handleEdit(row)">编辑</el-button> <!-- 点击编辑,传入当前行 -->
          <el-button size="small" type="danger" @click="handleDelete(row.id)">删除</el-button> <!-- 点击删除,传入当前行 id -->
        </template> <!-- 操作列插槽结束 -->
      </el-table-column> <!-- 操作列结束 -->
    </el-table> <!-- 表格结束 -->

    <el-pagination
      v-model:current-page="query.page"
      v-model:page-size="query.size"
      :total="total"
      :page-sizes="[10, 20, 50, 100]"
      layout="total, sizes, prev, pager, next, jumper"
      @current-change="getList"
      @size-change="getList"
    /> <!-- 分页组件,页码或每页条数变化时重新请求列表 -->

    <el-dialog v-model="dialogVisible" title="用户信息" width="500px"> <!-- 新增编辑弹窗 -->
      <el-form ref="formRef" :model="form" :rules="rules" label-width="100px"> <!-- 弹窗表单,绑定 form 和 rules -->
        <el-form-item label="用户名" prop="username"> <!-- 用户名表单项,prop 对应校验规则 -->
          <el-input v-model="form.username" /> <!-- 输入框绑定 form.username -->
        </el-form-item> <!-- 用户名表单项结束 -->

        <el-form-item label="状态"> <!-- 状态表单项 -->
          <el-select v-model="form.status"> <!-- 下拉框绑定 form.status -->
            <el-option label="启用" :value="1" /> <!-- 启用选项 -->
            <el-option label="禁用" :value="0" /> <!-- 禁用选项 -->
          </el-select> <!-- 下拉框结束 -->
        </el-form-item> <!-- 状态表单项结束 -->
      </el-form> <!-- 弹窗表单结束 -->

      <template #footer> <!-- 弹窗底部按钮区域 -->
        <el-button @click="dialogVisible = false">取消</el-button> <!-- 点击取消关闭弹窗 -->
        <el-button type="primary" @click="handleSubmit">确定</el-button> <!-- 点击确定提交表单 -->
      </template> <!-- 弹窗底部结束 -->
    </el-dialog> <!-- 弹窗结束 -->
  </div> <!-- 页面容器结束 -->
</template> <!-- 页面模板结束 -->

18. 常见坑

坑 1:表单校验不生效

必须保证这三个一致:

form.username // 表单字段
rules.username // 校验规则字段
prop="username" // 表单项 prop

坑 2:下拉框 value 类型错

<el-option label="启用" value="1" /> <!-- 字符串 1 -->
<el-option label="启用" :value="1" /> <!-- 数字 1 -->

后端要数字时,用 :value="1"

坑 3:搜索忘记重置页码

const handleSearch = () => { // 搜索方法
  query.page = 1 // 搜索时必须回到第 1 页
  getList() // 再请求列表
}

坑 4:不懂 row 是什么

<template #default="{ row }"> <!-- row 就是当前这一行的数据 -->

表格每一行都有自己的 row

坑 5:新增和编辑共用弹窗时忘记清空 form

新增时要清空:

form.id = null // 清空 id,表示新增
form.username = '' // 清空用户名
form.status = 1 // 设置默认状态

编辑时要回填:

form.id = row.id // 回填 id
form.username = row.username // 回填用户名
form.status = row.status // 回填状态