第5章 5.1 组件库:Element Plus 入门

🎯 开场:为什么你的页面写得像「毛坯房」?

上一章我们做完电商首页和详情页,有没有这种感觉:页面能跑,但怎么看怎么丑。按钮灰突突的,表格歪歪扭扭,输入框没有任何交互反馈……

这就是「自己造轮子」的代价。

就好比你装修房子,地板要自己浇筑、门要自己钉、灯要自己焊——不是不行,是没必要。把时间花在「为什么非得自己造门」这件事上,性价比太低了。

痛点来了:

  • 想做个好看的表格?得写几百行 CSS,还不一定对齐
  • 想做个表单验证?自己写逻辑能写到怀疑人生
  • 想做个加载状态、弹窗、通知?来来来,从头造

学完这章你能解决: 用 Element Plus 这个现成的「装修队」,让页面从「毛坯房」直接进化到「精装房」,而且代码量少到你不敢相信。


🧱 基础:Element Plus 到底是什么?

5.1.1 先说人话:Element Plus 是什么?

如果说 Vue 3 是一套「毛坯房建筑图纸」,那 Element Plus 就是\n\nSimple tech illustration expla\n\nAI comic creation scene, creat\n\n「精装房装修套餐」——里面包含了各种现成的组件:按钮、表单、表格、弹窗、导航栏……你只需要「组装」就行。

类比 Python 的世界:如果 requests 库让「发 HTTP 请求」变得简单,那 Element Plus 就是让「写后台管理页面」变得简单。

5.1.2 安装 Element Plus(2 分钟)

首先,我们要在项目里「引入装修队」:

npm install element-plus

然后在 main.ts 里引入(如果你用的是 Vite 项目):

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)  // 注册 Element Plus
app.mount('#app')

这 3 行代码,就是在告诉 Vue:「我请了一个装修队,后续页面装修就靠它了」。

5.1.3 第一个组件:Button 按钮

装修队进场,先装个「门把手」试试——哦不对,先放个按钮:

<template>
<div>
<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>
</div>
</template>

<script setup lang="ts">
// 不需要写任何 JS,el-button 是自带的组件
</script>

这行在干嘛: <el-button> 就是 Element Plus 提供的「按钮组件」,type 属性控制颜色风格,不用写一行 CSS。

运行后你得到 5 个配色好看的按钮:蓝色是「主要」,绿色是「成功」,橙色是「警告」,红色是「危险」。一个 CSS 都没写。

5.1.4 Table 表格:数据展示神器

电商后台最常见的就是「表格」——订单列表、用户列表、商品列表。传统方式要自己画表格、对齐表头、处理分页……Element Plus 一行搞定:

<template>
<el-table :data="products" stripe border style="width: 100%">
<el-table-column prop="name" label="商品名称" width="200" />
<el-table-column prop="price" label="价格" width="120" />
<el-table-column prop="stock" label="库存" width="100" />
<el-table-column label="操作">
  <template #default="scope">
    <el-button size="small" @click="handleEdit(scope.row)">编辑</el-button>
    <el-button size="small" type="danger" @click="handleDelete(scope.row)">删除</el-button>
  </template>
</el-table-column>
</el-table>
</template>

<script setup lang="ts">
import { ref } from 'vue'

// 商品数据
const products = ref([
{ name: 'iPhone 15', price: 6999, stock: 100 },
{ name: 'MacBook Pro', price: 12999, stock: 50 },
{ name: 'AirPods Pro', price: 1899, stock: 200 },
])

// 编辑操作
const handleEdit = (row: any) => {
console.log('编辑商品:', row.name)
}

// 删除操作
const handleDelete = (row: any) => {
console.log('删除商品:', row.name)
}
</script>

这行在干嘛:
- :data="products" 绑定数据源(就像给表格喂数据)
- prop="name" 指定显示哪一列
- #default="scope" 是插槽,用来放自定义内容(比如操作按钮)

stripe 让表格行交替变色(斑马纹),border 加上边框线——这两个属性就是「好看」的秘密。

5.1.5 Form 表单:数据录入必备

用户注册、商品上架……都离不开表单。Element Plus 的表单组件支持「数据绑定 + 验证」一条龙:

<template>
<el-form :model="form" :rules="rules" label-width="100px">
<el-form-item label="用户名" prop="username">
  <el-input v-model="form.username" placeholder="请输入用户名" />
</el-form-item>
<el-form-item label="邮箱" prop="email">
  <el-input v-model="form.email" placeholder="请输入邮箱" />
</el-form-item>
<el-form-item label="密码" prop="password">
  <el-input v-model="form.password" type="password" placeholder="请输入密码" show-password />
</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>
</template>

<script setup lang="ts">
import { reactive } from 'vue'
import { ElMessage } from 'element-plus'

// 表单数据
const form = reactive({
username: '',
email: '',
password: '',
})

// 验证规则
const rules = {
username: [
{ required: true, message: '请输入用户名', trigger: 'blur' },
{ min: 3, max: 10, message: '用户名3-10个字符', trigger: 'blur' },
],
email: [
{ required: true, message: '请输入邮箱', trigger: 'blur' },
{ type: 'email', message: '邮箱格式不正确', trigger: 'blur' },
],
password: [
{ required: true, message: '请输入密码', trigger: 'blur' },
{ min: 6, message: '密码至少6位', trigger: 'blur' },
],
}

// 提交表单
const submitForm = () => {
console.log('表单数据:', form)
ElMessage.success('提交成功!')
}

// 重置表单
const resetForm = () => {
form.username = ''
form.email = ''
form.password = ''
}
</script>

这行在干嘛:
- :model="form" 绑定表单数据(双向绑定)
- :rules="rules" 绑定验证规则
- prop="username" 关联验证规则和表单项
- ElMessage.success() 是 Element Plus 的「轻提示」,类似 Python 的 print() 但更好看

验证规则里的 required: truemin: 3type: 'email' 都是「开箱即用」的验证器,自己写?光邮箱正则就能折腾半天。


🔥 实战:3 个项目练手感

项目 1:5 分钟搞定「商品管理列表」

目标: 做一个能展示商品、能编辑删除的列表页。

<template>
<div style="padding: 20px;">
<h2>📦 商品管理</h2>

<!-- 表格区域 -->
<el-table :data="products" stripe border style="width: 100%; margin-top: 20px;">
  <el-table-column prop="id" label="ID" width="80" />
  <el-table-column prop="name" label="商品名称" />
  <el-table-column prop="category" label="分类" width="120" />
  <el-table-column prop="price" label="价格" width="100" />
  <el-table-column prop="stock" label="库存" width="100" />
  <el-table-column label="操作" width="180">
    <template #default="scope">
      <el-button size="small" type="primary" @click="editProduct(scope.row)">编辑</el-button>
      <el-button size="small" type="danger" @click="deleteProduct(scope.row)">删除</el-button>
    </template>
  </el-table-column>
</el-table>

<!-- 编辑弹窗 -->
<el-dialog v-model="dialogVisible" title="编辑商品" width="500px">
  <el-form :model="editForm" label-width="80px">
    <el-form-item label="商品名称">
      <el-input v-model="editForm.name" />
    </el-form-item>
    <el-form-item label="价格">
      <el-input-number v-model="editForm.price" :min="0" />
    </el-form-item>
    <el-form-item label="库存">
      <el-input-number v-model="editForm.stock" :min="0" />
    </el-form-item>
  </el-form>
  <template #footer>
    <el-button @click="dialogVisible = false">取消</el-button>
    <el-button type="primary" @click="confirmEdit">确定</el-button>
  </template>
</el-dialog>
</div>
</template>

<script setup lang="ts">
import { ref, reactive } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'

// 商品数据
const products = ref([
{ id: 1, name: 'iPhone 15', category: '手机', price: 6999, stock: 100 },
{ id: 2, name: 'MacBook Pro', category: '电脑', price: 12999, stock: 50 },
{ id: 3, name: 'AirPods Pro', category: '配件', price: 1899, stock: 200 },
])

// 编辑弹窗相关
const dialogVisible = ref(false)
const editForm = reactive({
id: 0,
name: '',
price: 0,
stock: 0,
})

// 编辑商品
const editProduct = (row: any) => {
editForm.id = row.id
editForm.name = row.name
editForm.price = row.price
editForm.stock = row.stock
dialogVisible.value = true
}

// 确认编辑
const confirmEdit = () => {
const product = products.value.find(p => p.id === editForm.id)
if (product) {
product.name = editForm.name
product.price = editForm.price
product.stock = editForm.stock
ElMessage.success('修改成功')
}
dialogVisible.value = false
}

// 删除商品
const deleteProduct = async (row: any) => {
try {
await ElMessageBox.confirm('确定要删除这个商品吗?', '提示', {
  type: 'warning',
})
const index = products.value.findIndex(p => p.id === row.id)
if (index > -1) {
  products.value.splice(index, 1)
  ElMessage.success('删除成功')
}
} catch {
// 用户取消
}
}
</script>

预期输出: 页面显示一个表格,有 3 条商品数据,每行有「编辑」和「删除」按钮。点击编辑会弹出对话框,删除会弹出确认框。

一句话解释: 这个项目把 Table + Dialog + MessageBox 组合起来,实现了「增删改查」的演示。真实项目中,数据会从后端 API 获取,下一章我们会讲到。


项目 2:15 分钟搞定「用户注册表单页」

目标: 做一个带完整验证的注册表单,支持密码确认、昵称选择、用户协议勾选。

<template>
<div class="register-container">
<el-card class="register-card">
  <template #header>
    <div class="card-header">
      <span>👤 用户注册</span>
    </div>
  </template>

  <el-form
    ref="formRef"
    :model="form"
    :rules="rules"
    label-width="100px"
    status-icon
  >
    <!-- 用户名 -->
    <el-form-item label="用户名" prop="username">
      <el-input v-model="form.username" placeholder="3-10位字母或数字" />
    </el-form-item>

    <!-- 邮箱 -->
    <el-form-item label="邮箱" prop="email">
      <el-input v-model="form.email" placeholder="用于找回密码" />
    </el-form-item>

    <!-- 密码 -->
    <el-form-item label="密码" prop="password">
      <el-input v-model="form.password" type="password" placeholder="至少6位" show-password />
    </el-form-item>

    <!-- 确认密码 -->
    <el-form-item label="确认密码" prop="confirmPassword">
      <el-input v-model="form.confirmPassword" type="password" placeholder="再输入一次" show-password />
    </el-form-item>

    <!-- 性别 -->
    <el-form-item label="性别" prop="gender">
      <el-radio-group v-model="form.gender">
        <el-radio label="male">男</el-radio>
        <el-radio label="female">女</el-radio>
        <el-radio label="other">保密</el-radio>
      </el-radio-group>
    </el-form-item>

    <!-- 年龄段 -->
    <el-form-item label="年龄段" prop="ageGroup">
      <el-select v-model="form.ageGroup" placeholder="请选择">
        <el-option label="18岁以下" value="under18" />
        <el-option label="18-25岁" value="18-25" />
        <el-option label="26-35岁" value="26-35" />
        <el-option label="35岁以上" value="above35" />
      </el-select>
    </el-form-item>

    <!-- 用户协议 -->
    <el-form-item prop="agreement">
      <el-checkbox v-model="form.agreement">
        我已阅读并同意<a href="#" style="color: #409eff;">《用户协议》</a>
      </el-checkbox>
    </el-form-item>

    <!-- 提交按钮 -->
    <el-form-item>
      <el-button type="primary" style="width: 100%;" @click="submitForm">
        注册
      </el-button>
    </el-form-item>
  </el-form>
</el-card>
</div>
</template>

<script setup lang="ts">
import { reactive, ref } from 'vue'
import { ElMessage, type FormInstance, type FormRules } from 'element-plus'

// 表单引用
const formRef = ref<FormInstance>()

// 表单数据
const form = reactive({
username: '',
email: '',
password: '',
confirmPassword: '',
gender: '',
ageGroup: '',
agreement: false,
})

// 自定义验证:确认密码
const validateConfirmPassword = (rule: any, value: any, callback: any) => {
if (value !== form.password) {
callback(new Error('两次输入的密码不一致'))
} else {
callback()
}
}

// 验证规则
const rules: FormRules = {
username: [
{ required: true, message: '请输入用户名', trigger: 'blur' },
{ pattern: /^[a-zA-Z0-9]{3,10}$/, message: '3-10位字母或数字', trigger: 'blur' },
],
email: [
{ required: true, message: '请输入邮箱', trigger: 'blur' },
{ type: 'email', message: '邮箱格式不正确', trigger: 'blur' },
],
password: [
{ required: true, message: '请输入密码', trigger: 'blur' },
{ min: 6, message: '密码至少6位', trigger: 'blur' },
],
confirmPassword: [
{ required: true, message: '请确认密码', trigger: 'blur' },
{ validator: validateConfirmPassword, trigger: 'blur' },
],
gender: [
{ required: true, message: '请选择性别', trigger: 'change' },
],
ageGroup: [
{ required: true, message: '请选择年龄段', trigger: 'change' },
],
agreement: [
{ validator: (rule, value, callback) => {
  value ? callback() : callback(new Error('请勾选用户协议'))
}, trigger: 'change' },
],
}

// 提交表单
const submitForm = async () => {
if (!formRef.value) return

await formRef.value.validate((valid) => {
if (valid) {
  console.log('注册数据:', form)
  ElMessage.success('注册成功!即将跳转到登录页...')
} else {
  ElMessage.error('请检查表单填写是否正确')
}
})
}
</script>

<style scoped>
.register-container {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
background: #f0f2f5;
}

.register-card {
width: 500px;
}

.card-header {
font-size: 18px;
font-weight: bold;
}
</style>

预期输出: 一个居中的注册卡片,包含用户名、邮箱、密码、确认密码(带一致性验证)、性别单选、年龄段下拉选择、协议勾选。填写错误会有红色提示,填写正确点击注册显示成功消息。

一句话解释: 这个项目展示了 Form 的完整能力:多种输入组件(Input/Select/Radio/Checkbox)、内置验证规则、自定义验证函数(密码一致性)、以及提交时的整体验证。


项目 3:15 分钟搞定「仪表盘首页」

目标: 把前两个项目的组件组合起来,做一个电商后台的仪表盘首页。

<template>
<div class="dashboard">
<!-- 顶部导航 -->
<el-menu mode="horizontal" :default-active="activeMenu" class="top-menu">
  <el-menu-item index="1">📊 数据概览</el-menu-item>
  <el-menu-item index="2">📦 商品管理</el-menu-item>
  <el-menu-item index="3">👥 用户管理</el-menu-item>
  <el-menu-item index="4">📝 订单管理</el-menu-item>
</el-menu>

<!-- 统计卡片 -->
<el-row :gutter="20" style="margin: 20px 0;">
  <el-col :span="6">
    <el-card shadow="hover">
      <div class="stat-card">
        <div class="stat-value">¥ 128,399</div>
        <div class="stat-label">今日销售额</div>
        <el-tag type="success" size="small">+12.5% ↑</el-tag>
      </div>
    </el-card>
  </el-col>
  <el-col :span="6">
    <el-card shadow="hover">
      <div class="stat-card">
        <div class="stat-value">1,234</div>
        <div class="stat-label">今日订单</div>
        <el-tag type="success" size="small">+8.2% ↑</el-tag>
      </div>
    </el-card>
  </el-col>
  <el-col :span="6">
    <el-card shadow="hover">
      <div class="stat-card">
        <div class="stat-value">89</div>
        <div class="stat-label">待发货</div>
        <el-tag type="warning" size="small">需处理</el-tag>
      </div>
    </el-card>
  </el-col>
  <el-col :span="6">
    <el-card shadow="hover">
      <div class="stat-card">
        <div class="stat-value">3.2%</div>
        <div class="stat-label">退货率</div>
        <el-tag type="danger" size="small">-0.5% ↓</el-tag>
      </div>
    </el-card>
  </el-col>
</el-row>

<!-- 最新订单列表 -->
<el-card style="margin: 0 20px;">
  <template #header>
    <div class="card-header">
      <span>📋 最新订单</span>
      <el-button type="primary" size="small" text>查看全部</el-button>
    </div>
  </template>

  <el-table :data="recentOrders" stripe>
    <el-table-column prop="orderId" label="订单号" width="150" />
    <el-table-column prop="customer" label="客户" width="120" />
    <el-table-column prop="product" label="商品" />
    <el-table-column prop="amount" label="金额" width="100">
      <template #default="scope">
        ¥{{ scope.row.amount.toFixed(2) }}
      </template>
    </el-table-column>
    <el-table-column prop="status" label="状态" width="100">
      <template #default="scope">
        <el-tag :type="getStatusType(scope.row.status)">
          {{ scope.row.statusText }}
        </el-tag>
      </template>
    </el-table-column>
    <el-table-column prop="createTime" label="下单时间" width="180" />
  </el-table>
</el-card>

<!-- 消息通知 -->
<el-card style="margin: 20px;">
  <template #header>
    <span>🔔 系统通知</span>
  </template>
  <el-empty v-if="notifications.length === 0" description="暂无新通知" />
  <el-list v-else>
    <el-list-item v-for="item in notifications" :key="item.id">
      <el-badge :value="item.new ? '新' : ''" :hidden="!item.new">
        <span>{{ item.content }}</span>
      </el-badge>
    </el-list-item>
  </el-list>
</el-card>
</div>
</template>

<script setup lang="ts">
import { ref } from 'vue'

// 当前激活的菜单
const activeMenu = ref('1')

// 最新订单数据
const recentOrders = ref([
{ orderId: 'DD20240101001', customer: '张三', product: 'iPhone 15', amount: 6999, status: 'pending', statusText: '待发货', createTime: '2024-01-15 10:30:22' },
{ orderId: 'DD20240101002', customer: '李四', product: 'MacBook Pro', amount: 12999, status: 'shipped', statusText: '已发货', createTime: '2024-01-15 11:15:08' },
{ orderId: 'DD20240101003', customer: '王五', product: 'AirPods Pro', amount: 1899, status: 'completed', statusText: '已完成', createTime: '2024-01-15 14:22:45' },
{ orderId: 'DD20240101004', customer: '赵六', product: 'iPad Air', amount: 4399, status: 'pending', statusText: '待发货', createTime: '2024-01-15 16:05:33' },
])

// 系统通知
const notifications = ref([
{ id: 1, content: '您有 3 个订单等待发货处理', new: true },
{ id: 2, content: '商品「iPhone 15」库存不足,请及时补货', new: true },
{ id: 3, content: '系统将于今晚 23:00 进行维护升级', new: false },
])

// 获取状态标签类型
const getStatusType = (status: string) => {
const typeMap: Record<string, any> = {
pending: 'warning',
shipped: 'primary',
completed: 'success',
cancelled: 'info',
}
return typeMap[status] || 'info'
}
</script>

<style scoped>
.dashboard {
background: #f5f7fa;
min-height: 100vh;
}

.top-menu {
padding: 0 20px;
}

.card-header {
display: flex;
justify-content: space-between;
align-items: center;
}

.stat-card {
text-align: center;
padding: 10px 0;
}

.stat-value {
font-size: 28px;
font-weight: bold;
color: #303133;
margin-bottom: 8px;
}

.stat-label {
font-size: 14px;
color: #909399;
margin-bottom: 8px;
}
</style>

预期输出: 一个完整的仪表盘页面,包含顶部导航、4 个统计卡片(销售额/订单数/待发货/退货率)、最新订单表格(带状态标签)、系统通知列表。

一句话解释: 这个项目展示了 Element Plus 的「组合能力」——Menu、Row/Col(栅格布局)、Card、Tag、Badge、Empty 等组件组合在一起,形成了看起来很专业的后台首页。


💪 进阶:5 个新人必踩的坑

坑 1:表格数据变了,但页面没更新

❌ 错误写法:
const products = [
{ name: 'iPhone', price: 6999 },
]
// 直接修改数组,Vue 检测不到
products[0].price = 5999  // 页面不会更新!
✅ 正确写法:
import { ref } from 'vue'

const products = ref([
{ name: 'iPhone', price: 6999 },
])
// 通过 .value 修改,Vue 能检测到
products.value[0].price = 5999  // 页面更新了

原因: Element Plus 的 :data 绑定的是响应式数据(refreactive),普通数组不是响应式的。


坑 2:Dialog 弹窗关闭后,数据还残留

❌ 错误写法:
const dialogVisible = ref(false)
const editForm = reactive({ name: '', price: 0 })

const openDialog = () => {
dialogVisible.value = true
// 没清空 editForm,上次数据会残留
}
✅ 正确写法:
const dialogVisible = ref(false)
const editForm = reactive({ id: 0, name: '', price: 0 })

const openDialog = (row) => {
dialogVisible.value = true
// 打开前先重置数据
Object.assign(editForm, { id: row.id, name: row.name, price: row.price })
}

const closeDialog = () => {
dialogVisible.value = false
// 关闭后清空表单
editForm.id = 0
editForm.name = ''
editForm.price = 0
}

坑 3:表单验证不触发

❌ 错误写法:
<el-form :model="form" :rules="rules">
<el-form-item label="邮箱" prop="email">
<el-input v-model="form.email" />
</el-form-item>
<!-- 缺少 ref -->
</el-form>
✅ 正确写法:
<template>
<el-form ref="formRef" :model="form" :rules="rules">
<!-- 表单内容 -->
</el-form>
</template>

<script setup lang="ts">
import { ref } from 'vue'
import type { FormInstance } from 'element-plus'

const formRef = ref<FormInstance>()  // 一定要定义这个 ref

const submit = async () => {
await formRef.value?.validate()  // 调用 validate 方法
}
</script>

原因: :rules 只是声明规则,实际验证需要通过 formRef.value.validate() 手动触发。


坑 4:DatePicker 返回的格式不对

❌ 错误做法:
const handleDateChange = (date) => {
console.log(date)  // 打印出来是 Date 对象,不是字符串
// 直接传给后端可能报错
}
✅ 正确做法:
<el-date-picker
v-model="form.date"
type="date"
placeholder="选择日期"
format="YYYY-MM-DD"      // 格式化显示
value-format="YYYY-MM-DD" // 格式化值
/>

原因: DatePicker 的 value-format 属性控制绑定的值是什么格式,不设置的话默认是 Date 对象。


坑 5:Select 多选模式下值是数组但验证写错了

❌ 错误写法:
const rules = {
tags: [{ required: true, message: '请选择标签', trigger: 'change' }],
}
// 多选时,form.tags 是数组 [],required: true 对空数组会失效
✅ 正确写法:
const rules = {
tags: [
{ required: true, message: '请选择标签', trigger: 'change' },
{ type: 'array', min: 1, message: '至少选择一个标签', trigger: 'change' },
],
}

调试技巧:如何排查 Element Plus 组件问题?

当你发现组件表现不符合预期时,可以这样做:

1. 检查数据绑定是否正确:

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

<!-- 疑难杂症时,加个隐藏的调试输出 -->
<pre>{{ JSON.stringify(form, null, 2) }}</pre>

2. 使用 Element Plus 官方调试工具:

浏览器安装「Vue DevTools」插件,选择「Element Plus」标签页,可以看到每个组件的内部状态。

3. 查看官方文档的「 playground」:

Element Plus 官网每个组件都有在线示例,直接复制下来改一改就能用。


✏️ 练习题

练习 1(2 分钟):换个图标按钮
- 输入:在项目 1 的表格里,把「编辑」按钮改成 type="warning"
- 预期输出:按钮变成橙色
- 提示:按钮的 type 属性控制颜色

练习 2(3 分钟):给表格加一列
- 输入:在项目 1 的商品表格里,加一列「分类」,数据为 { category: '手机' }
- 预期输出:表格多出一列「分类」
- 提示:参考现有的 el-table-column 写法

练习 3(5 分钟):添加邮箱验证
- 输入:在项目 2 的表单里,把「邮箱」字段的验证规则改成 type: 'email'
- 预期输出:输入非邮箱格式会提示「邮箱格式不正确」
- 提示:Element Plus 内置了 type: 'email' 验证器

练习 4(8 分钟):把项目 1 和项目 2 串起来
- 输入:在项目 1 的「编辑」弹窗里,加入用户名和邮箱两个字段,并添加验证
- 预期输出:编辑弹窗打开时能修改用户名和邮箱,点击确定时验证通过才关闭
- 提示:参考项目 2 的表单验证写法

练习 5(5 分钟):分析这个报错
- 输入:报错信息是 TypeError: Cannot read properties of undefined (reading 'validate')
- 预期输出:说出原因并修复
- 提示:检查 formRef 是否正确定义和关联


作业:做一个「任务管理仪表盘」

  • 需求描述: 做一个团队任务管理的小工具,用来查看和跟踪任务进度
  • 功能点:
    1. 顶部导航栏(首页/任务列表/成员管理)
    2. 4 个统计卡片(总任务/进行中/已完成/已逾期)
    3. 任务表格(任务名/负责人/状态/截止日期),状态用 Tag 显示
    4. 点击「标记完成」按钮,任务状态变化
  • 加分项:
    1. 给表格加上「截止日期」排序
    2. 用 el-date-picker 筛选特定日期范围的任务
  • 验收标准: 能跑起来 + 表格能显示数据 + 点击按钮状态会变化
  • 提交方式: 评论区贴代码或 GitHub 链接

📚 总结

本文学到的 3 个核心点:

  1. Element Plus 是 Vue 3 的「精装房套餐」——各种 UI 组件开箱即用,不用自己造轮子
  2. Table + Form 是后台系统的两大核心——表格展示数据,表单录入数据,两者都支持数据验证
  3. 响应式是 Vue 的精髓——数据变了页面才会变,用 ref / reactive 包装数据是基本功

延伸学习资源:


互动钩子: 你在写后台页面时,最头疼的是哪个部分?是表格复杂的筛选排序,还是表单的各种验证规则?评论区聊聊,老粉优先回复!

下一章我们要聊的是「移动端」的 UI 库——如果你觉得 Element Plus 是给 PC 端用的,那下一章的 Vant 就是移动端的 Element Plus,专门解决「手机网页怎么做才好看」这个问题。敬请期待!

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。