第11次 · 引入 Element Plus 与全局配置
第11次 · 引入 Element Plus 与全局配置
第1/7页 · 先知道今天要做什么
从今天起进入第二阶段。第一阶段你学会了自己写组件;这一阶段开始用别人写好的组件——Element Plus,国内用得最广的 Vue 3 组件库。它能让你在几分钟内做出公司里那种“看起来很专业”的后台界面。
但用之前必须解决三件事:
- 怎么把组件库引进项目(三种方式,各有取舍);
- 怎么查看文档、知道有哪些组件、有哪些属性(这是本阶段最重要的技能);
- 怎么一次性设置全局默认(默认尺寸、语言、弹层层级),避免每个组件都手写一遍。
第 1 课你已经在“手动 import”的方式下用过了十几个组件,今天把这件事系统讲清楚。
今天的场景
做一个“组件库能力检查页”。左上角两个开关:一个切换组件的默认尺寸,一个切换界面语言(中文 / English)。下面放一排典型组件(按钮、输入框、下拉、日期选择、分页、提示)。切换开关时,整页组件的尺寸和文字一起变——这就是全局配置的价值。
下课时拿出这三样结果
| 做到什么 | 在哪里看 | 完成的证据 |
|---|---|---|
| 说得清三种引入方式的区别 | 页面与讲解 | 能说出“完整引入 / 手动按需 / 自动按需”各自代价,并知道本项目用的是哪种。 |
会用 ElConfigProvider 做全局配置 |
左上角两个开关 | 切换尺寸时所有组件变小/变大;切换语言时分页与日期控件的文字变成英文。 |
| 会查文档 | 现场演示 | 能自己找到任意组件的属性表、事件表、插槽表,并把一个新属性用对。 |
你只需要带着这些基础来
第 1—10 课的全部内容。今天不写复杂逻辑,重点在“怎么用组件库”这件事本身。
本课时 45 分钟怎么上
| 时间 | 老师带着做 | 学生留下什么 |
|---|---|---|
| 0—5 分钟 | 打开 Element Plus 官网,演示“找组件 → 看示例 → 复制 → 改”的完整流程。 | 会自己查文档。 |
| 5—15 分钟 | 讲三种引入方式与各自的体积代价;讲本项目为什么用手动 import。 | 笔记里写下三种方式。 |
| 15—30 分钟 | 讲 ElConfigProvider:size、locale、zIndex、namespace。 |
能说出它“包住谁就影响谁”。 |
| 30—42 分钟 | 粘贴本课 App.vue,切换两个开关观察全局变化。 |
两种切换都生效。 |
| 42—45 分钟 | 抽查:问“为什么要手动 import 每个组件”。 | 全员提交。 |
从哪里开始
复制第 10 课的工程,改名 lesson-vue-11。不需要新增依赖(element-plus 在第 1 课就装好了)。
今天先掌握到这里
第 12 课讲布局(栅格与容器),第 13 课开始逐个讲基础组件。
来源:本课自编 Vue 3 前端核心技能实训 · 语法依据 Vue 3.5 官方文档 · 组件依据 Element Plus 2.8 官方文档
第2/7页 · 把新词说清楚
新词与本课含义
| 名字 | 用熟悉的话理解 | 本课里长什么样 |
|---|---|---|
| 组件库 | 别人写好的一整套界面组件,直接拿来用。 | element-plus |
| 全局注册 | 一次注册,所有组件全都能用(app.use(...))。 |
app.use(ElementPlus) |
| 按需引入 | 只引入用到的组件,打包体积小。 | import { ElButton } from 'element-plus' |
| 全局配置 | 一次性设置默认尺寸、语言等,所有组件共享。 | <el-config-provider :size="size"> |
locale |
语言包,决定组件内部的文字(“共 N 条”“确定”)。 | zh-cn / en |
ElConfigProvider |
一个“壳组件”,包住谁就影响谁。 | 一般包在 App.vue 最外层 |
三种引入方式
| 方式 | 怎么写 | 优点 | 缺点 | 什么时候用 |
|---|---|---|---|---|
| 完整引入 | app.use(ElementPlus) + 引入全量样式 |
省事,一行搞定 | 打包体积最大(用不到的都进来了) | 学习阶段、小项目 |
| 手动按需 | 每个组件单独 import |
体积最小,依赖关系最清楚 | 每个文件都要写 import 列表 | 本课程所有课时都用这种 |
| 自动按需 | 装 unplugin-vue-components 等插件,配置一次后不用手写 import |
兼顾体积与便利 | 要多装两个插件、配置 vite.config.js |
正式项目最常用 |
为什么本课程坚持用手动按需? 因为你从代码第一行就能看清“这个文件到底用了哪些组件”。学习阶段最怕的就是“它怎么突然就能用了”——自动导入会让这件事变得不透明。等第 39 课讲工程化时再了解自动按需的配置。
手动按需的两行固定套路
<script setup>
// ① 引入这个文件用到的组件(组件名就是 el-xxx 的大驼峰写法)
import { ElButton, ElInput, ElDatePicker } from 'element-plus'
// ② 引入样式(本课程放在每个文件里,保证单独粘贴即可运行)
import 'element-plus/dist/index.css'
</script>
写法规则:模板里写 <el-button>,import 时写 ElButton。中间横线转大驼峰,前面加 El。
ElConfigProvider 能配置什么
| 属性 | 作用 | 常见值 |
|---|---|---|
size |
所有组件的默认尺寸 | 'large' / 'default' / 'small' |
locale |
语言包 | 中文 zhCn / 英文 en |
z-index |
弹层的起始层级 | 数字,弹窗被别的东西挡住时调它 |
namespace |
给所有类名加前缀(多主题项目用) | 字符串 |
语言包的引入路径:
import zhCn from 'element-plus/es/locale/lang/zh-cn'
import en from 'element-plus/es/locale/lang/en'
注意:ElConfigProvider 是“包住谁、影响谁”。 如果只包了页面的一部分,那一部分之外的组件不受影响。所以通常放在最外层包住全部内容。
只看这几行:全局配置的最小写法
<script setup>
import { ref } from 'vue'
import { ElConfigProvider, ElButton, ElPagination } from 'element-plus'
import zhCn from 'element-plus/es/locale/lang/zh-cn'
import en from 'element-plus/es/locale/lang/en'
import 'element-plus/dist/index.css'
const size = ref('default')
const locale = ref(zhCn)
</script>
<template>
<el-config-provider :size="size" :locale="locale">
<el-button>按钮会跟着尺寸变</el-button>
<el-pagination :total="100" layout="total, prev, pager, next" />
</el-config-provider>
</template>
先口头预测:把 size 改成 'small',那些显式写了 size="large" 的按钮会跟着变小吗?
不会。 全局配置只是“默认值”。某个组件自己写了 size,就优先用它自己的。这和 CSS 里“就近原则”是一个道理——越具体越优先。
来源:本课自编 Vue 3 前端核心技能实训 · 语法依据 Vue 3.5 官方文档 · 组件依据 Element Plus 2.8 官方文档
第3/7页 · 先看一个小例子
完整代码:App.vue(组件库能力检查页)
<script setup>
import { ref, computed } from 'vue'
import {
ElConfigProvider, ElCard, ElRow, ElCol, ElRadioGroup, ElRadioButton,
ElButton, ElButtonGroup, ElInput, ElSelect, ElOption, ElDatePicker,
ElPagination, ElSwitch, ElTag, ElDivider, ElAlert, ElSpace,
ElMessage, ElNotification, ElMessageBox
} from 'element-plus'
import zhCn from 'element-plus/es/locale/lang/zh-cn'
import en from 'element-plus/es/locale/lang/en'
import 'element-plus/dist/index.css'
// 全局默认尺寸与语言
const size = ref('default') // large | default | small
const lang = ref('zh') // zh | en
const locale = computed(() => (lang.value === 'zh' ? zhCn : en))
// 受控数据
const kw = ref('')
const city = ref('')
const date = ref('')
const page = ref(1)
const autoRefresh = ref(true)
function hello() {
ElMessage.success(lang.value === 'zh' ? '你好,Element Plus!' : 'Hello, Element Plus!')
}
function notify() {
ElNotification({
title: lang.value === 'zh' ? '通知标题' : 'Notification',
message: lang.value === 'zh' ? '这是一条右上角通知' : 'This is a notification',
type: 'success'
})
}
function confirm() {
ElMessageBox.confirm(
lang.value === 'zh' ? '确定要执行这个操作吗?' : 'Are you sure?',
lang.value === 'zh' ? '提示' : 'Tip',
{ type: 'warning' }
).then(() => ElMessage.info(lang.value === 'zh' ? '已确认' : 'Confirmed'))
.catch(() => ElMessage.info(lang.value === 'zh' ? '已取消' : 'Cancelled'))
}
</script>
<template>
<!-- ElConfigProvider 包住全部内容:里面的组件都继承这里的默认设置 -->
<el-config-provider :size="size" :locale="locale">
<div class="page">
<h1 class="title">Element Plus 能力检查页</h1>
<el-card class="block">
<template #header>全局配置(改这里,整页跟着变)</template>
<div class="bar">
<span class="label">默认尺寸:</span>
<el-radio-group v-model="size">
<el-radio-button value="large">large</el-radio-button>
<el-radio-button value="default">default</el-radio-button>
<el-radio-button value="small">small</el-radio-button>
</el-radio-group>
<span class="label">界面语言:</span>
<el-radio-group v-model="lang">
<el-radio-button value="zh">中文</el-radio-button>
<el-radio-button value="en">English</el-radio-button>
</el-radio-group>
</div>
<el-alert
title="注意:下面凡是自己写了 size 属性的组件,不会被全局尺寸覆盖(就近优先)。"
type="info" :closable="false" show-icon style="margin-top: 12px"
/>
</el-card>
<el-row :gutter="16">
<el-col :span="12">
<el-card class="block">
<template #header>基础组件</template>
<p class="label">按钮(含按钮组)</p>
<el-space wrap>
<el-button type="primary">主要按钮</el-button>
<el-button>普通按钮</el-button>
<el-button type="success" plain>成功</el-button>
<el-button type="danger" disabled>禁用</el-button>
<el-button size="large">我显式写了 large</el-button>
</el-space>
<el-divider />
<p class="label">输入框 / 下拉 / 日期</p>
<el-space direction="vertical" fill style="width: 100%">
<el-input v-model="kw" placeholder="请输入关键字" clearable />
<el-select v-model="city" placeholder="请选择城市" style="width: 100%">
<el-option label="北京" value="bj" />
<el-option label="上海" value="sh" />
<el-option label="广州" value="gz" />
</el-select>
<el-date-picker v-model="date" type="date" placeholder="选择日期" style="width: 100%" />
</el-space>
</el-card>
</el-col>
<el-col :span="12">
<el-card class="block">
<template #header>反馈类组件(文字会跟着语言变)</template>
<el-space wrap>
<el-button type="primary" @click="hello">消息提示 Message</el-button>
<el-button @click="notify">通知 Notification</el-button>
<el-button @click="confirm">确认框 MessageBox</el-button>
</el-space>
<el-divider />
<p class="label">分页(“共 N 条”会随语言变化)</p>
<el-pagination
v-model:current-page="page"
:total="268"
:page-size="20"
layout="total, prev, pager, next, jumper"
background
/>
<el-divider />
<p class="label">其他</p>
<el-space wrap>
<el-switch v-model="autoRefresh" active-text="自动刷新" />
<el-tag type="success">标签</el-tag>
<el-tag type="warning" effect="dark">深色标签</el-tag>
<el-tag type="info" closable>可关闭</el-tag>
</el-space>
</el-card>
</el-col>
</el-row>
<el-card class="block">
<template #header>当前状态(自查用)</template>
<p>默认尺寸:<code>{{ size }}</code> 语言:<code>{{ lang }}</code></p>
<p>关键字:<code>{{ kw || '(空)' }}</code> 城市:<code>{{ city || '(未选)' }}</code> 日期:<code>{{ date || '(未选)' }}</code></p>
<p>当前页:<code>{{ page }}</code> 自动刷新:<code>{{ autoRefresh }}</code></p>
</el-card>
</div>
</el-config-provider>
</template>
<style>
html, body, #app {
margin: 0; padding: 0; max-width: none; width: auto; height: auto;
display: block; place-items: initial; text-align: left; background: #f5f7fa;
}
</style>
<style scoped>
.page { max-width: 1100px; margin: 28px auto; padding: 0 16px; }
.title { font-size: 22px; color: #303133; margin: 0 0 18px; }
.block { margin-bottom: 16px; }
.bar { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.label { color: #606266; font-size: 13px; margin: 0 0 8px; }
code { background: #f0f2f5; padding: 1px 5px; border-radius: 4px; color: #c7254e; }
</style>
预期看见什么
- 顶部一张卡片,两组单选按钮(尺寸 / 语言)。
- 下面左右两栏组件展示区。
- 把“默认尺寸”切到
small:按钮、输入框、下拉、分页整体变小;但那个写了size="large"的按钮保持不变。 - 把语言切成
English:分页里的“共 268 条”变成 “Total 268”,日期选择框的“选择日期”变成 “Pick a date”,确认框的按钮变成 OK / Cancel。 - 点三个反馈按钮,分别弹出消息提示、右上角通知、确认对话框。
- 底部“当前状态”实时显示各控件的值。
先猜一猜,读完代码再回答
为什么 locale 要用 computed 而不是直接写 ref(zhCn)?
const lang = ref('zh')
const locale = computed(() => (lang.value === 'zh' ? zhCn : en))
因为语言包对象本身不会变,变的是“选哪个语言包”这件事。 用 computed 把“当前选中语言”这个状态派生出真正要传给组件的语言包对象——这正是第 4 课那条原则:能用已有数据算出来的,就不要单独存一份。 如果写成 const locale = ref(zhCn),你就得在两个地方同时维护 lang 和 locale,一定会忘。
来源:本课自编 Vue 3 前端核心技能实训 · 语法依据 Vue 3.5 官方文档 · 组件依据 Element Plus 2.8 官方文档
第4/7页 · 一步一步做出来
第1步:确认依赖已经装好
npm install element-plus
打开 package.json,预期:dependencies 里能看到 "element-plus": "^2.x"。没装就先装,后面全课都依赖它。
第2步:最小验证——引入一个按钮
<script setup>
import { ElButton } from 'element-plus'
import 'element-plus/dist/index.css'
</script>
<template>
<el-button type="primary">我是一个组件库按钮</el-button>
</template>
预期:按钮是蓝色的、有圆角,和普通 <button> 明显不同。如果样式没生效,99% 是忘了第二行样式引入。
第3步:故意不引入样式,看会发生什么
把 import 'element-plus/dist/index.css' 注释掉,刷新。预期:按钮变成浏览器默认的灰色方块。记住这个现象——以后遇到“组件能用但没样式”,第一件事就是查这行。
第4步:体验全局尺寸
<script setup>
import { ref } from 'vue'
import { ElConfigProvider, ElButton } from 'element-plus'
import 'element-plus/dist/index.css'
const size = ref('large')
</script>
<template>
<el-config-provider :size="size">
<el-button>跟着变</el-button>
<el-button size="small">不跟着变(我自己写了)</el-button>
</el-config-provider>
</template>
把 size 从 large 改成 small,预期:第一个按钮变小,第二个始终是小的。这验证了“就近优先”。
第5步:体验语言包
加入英文语言包与切换,观察分页与日期组件的文字。预期:文案整体切到英文。中文项目默认就是中文,不必额外配置;但如果你的界面文字出现英文(例如“Total”),就是语言包没配。
第6步:学会查文档(本课最重要的动作)
打开 Element Plus 官网,找到 el-input 页面,做三件事:
- 找到 API 表格,数一数它有多少个属性;
- 找出
clearable、show-password、maxlength三个属性分别是什么作用; - 找到 Events 表格里的
clear与change,说出它们分别在什么时候触发。
然后在自己的页面里用上 show-password,预期:输入框右侧出现一只眼睛图标。
第7步:整段替换为本课完整版
把第 3 页的完整 App.vue 覆盖 src/App.vue,把两个切换开关都试一遍。
本课文件速查
| 位置 | 本次作用 |
|---|---|
import { ... } from 'element-plus' |
手动按需引入,列出本文件用到的所有组件。 |
import 'element-plus/dist/index.css' |
引入组件库样式,忘写就没样式。 |
ElConfigProvider |
全局配置入口,包住全部内容。 |
size / lang → locale |
全局尺寸与语言,后者由前者派生。 |
ElMessage / ElNotification / ElMessageBox |
三个函数式反馈组件,直接调用即用。 |
完成修改后检查
| 操作或输入 | 预期观察 |
|---|---|
切到 small |
大部分组件变小,显式写了 size 的不变。 |
| 切到 English | 分页、日期、确认框文字变英文。 |
| 点三个反馈按钮 | 三种不同类型的提示都出现。 |
| 注释掉样式引入 | 组件失去样式(记得改回来)。 |
给输入框加 show-password |
出现密码可见切换图标。 |
来源:本课自编 Vue 3 前端核心技能实训 · 语法依据 Vue 3.5 官方文档 · 组件依据 Element Plus 2.8 官方文档
第5/7页 · 换成自己的代码
你的任务
- 建一个自己的“组件清单页”:至少引入 10 个不同组件,每个下面写一句“它适合用在什么场景”。
- 加三个全局配置项:
size之外,再加两个(例如用单选按钮切z-index的起始值,以及一个“是否开启圆角”的自定义开关,用class控制)。 - 查文档并新引入两个组件:要求是你以前没用过的(建议:
el-skeleton骨架屏、el-result结果页、el-timeline时间线任选两个)。 - 做一个“按钮尺寸对照表”:同一行放
large/default/small三个按钮,标注哪个会跟随全局变化。 - 写清一个结论:分别用 3 句话说明“完整引入、手动按需、自动按需”的差别,并说明本课程为什么选手动按需。
按这张操作单完成
| 步骤 | 改哪里 | 运行后应该看到什么 |
|---|---|---|
| 1 组件清单 | 模板新增 | 10 个组件都能正常显示。 |
| 2 加配置 | ElConfigProvider 属性 |
切换时确实有全局变化。 |
| 3 新组件 | 查文档后引入 | 两个新组件按文档示例跑通。 |
| 4 尺寸表 | 三个按钮并排 | 能指出哪个不受全局影响。 |
| 5 写结论 | 练习记录.md |
三句话结论写在记录里。 |
最低完成标准:先把这三项做实
| 检查项 | 通过条件 |
|---|---|
| 引入正确 | 用到的每个组件都在 import 列表里,且页面无“组件未定义”报错。 |
| 全局配置生效 | 切换尺寸/语言后,页面有肉眼可见的整体变化。 |
| 会查文档 | 能当场打开文档找到某个组件的属性表并正确使用一个属性。 |
在本地写练习记录
- 抄下“不引入样式”时的现象。
- 记录“就近优先”实验:显式
size="large"的按钮在全局small时是否变化。 - 写下你新查到的两个组件的属性列表(每个至少 3 个属性)。
最后交什么
提交 src/App.vue 与 练习记录.md。
来源:本课自编 Vue 3 前端核心技能实训 · 语法依据 Vue 3.5 官方文档 · 组件依据 Element Plus 2.8 官方文档
第6/7页 · 出错时从哪里查
把现象和检查动作对上
| 看到什么现象 / 报错 | 先检查哪里 | 修好后怎样确认 |
|---|---|---|
页面报 Failed to resolve component: el-xxx |
忘了在 <script setup> 里 import 这个组件。 |
补上 import 后正常显示。 |
| 组件显示出来了,但完全没有样式 | 忘了 import 'element-plus/dist/index.css'。 |
补上后样式正常。 |
引入 element-plus 报找不到模块 |
没执行 npm install element-plus,或不在项目目录里执行了命令。 |
package.json 里能看到依赖。 |
ElConfigProvider 配了但没效果 |
它没有包住那些组件(只包了一部分)。 | 放到最外层后全部生效。 |
| 中文界面里出现英文(如 “Total”) | 语言包没配,默认是英文。 | 配 :locale="zhCn" 后变中文。 |
| 弹窗被页面上的某些元素挡住 | z-index 冲突。 |
用 ElConfigProvider 的 :z-index 提高起始层级。 |
import 的组件名写错(Elbutton) |
大小写必须准确:El + 大驼峰。 |
改对后正常。 |
排错口诀
组件看不见,先查 import; 样式全丢了,补 index.css; 全局不生效,看它包住了谁; 英文冒出来,是语言包没配。
不要用这些办法“修复”
- 不要为了省事改成
app.use(ElementPlus)完整引入——本课程后续每课的App.vue都靠手动 import 保持独立可运行,混用会导致“有的课能跑、有的课不能跑”。 - 不要把
import 'element-plus/dist/index.css'只写在main.js里。虽然那样也能生效,但本课程的单文件粘贴方案要求样式引入跟着App.vue走。 - 不要为了让尺寸统一而给每个组件都手写
size——那样全局配置就失去意义了,维护成本也高。
需要老师帮忙时交这些
出问题那个组件的完整标签、你的 import 列表、package.json 里 element-plus 的版本、控制台报错原文。
老师巡视时只问三句话
- 这个组件是怎么来的?在哪一行引入的?(能指出 import)
- 你的全局配置包住了哪些内容?(能指出
ElConfigProvider的范围) - 这个属性你是怎么知道要写的?(能说出查文档的过程,而不是猜)
来源:本课自编 Vue 3 前端核心技能实训 · 语法依据 Vue 3.5 官方文档 · 组件依据 Element Plus 2.8 官方文档
第7/7页 · 用自己的话讲一遍
回到第 3 页:你刚才猜对了吗?
为什么 locale 要用 computed?
参考解释:真正会变的是“选中了哪种语言”这个状态(lang)。locale 只是由它派生出来的结果:选中文就用中文包,选英文就用英文包。用 computed 写,就只有一个数据源,永远不会出现“状态是中文而语言包是英文”的矛盾。
回答本课的两个问题
| 问题 | 参考解释 |
|---|---|
| 三种引入方式怎么选? | 学习与小项目用完整引入;正式项目用自动按需;本课程用手动按需,因为它让“用了什么”一目了然,且单文件可独立运行。 |
| 全局配置和组件自己的属性谁优先? | 组件自己的属性优先。全局配置只是“默认值”,越具体的设置越优先。 |
五个必须能答上来的问题
| 考考自己 | 可以这样通俗回答 |
|---|---|
模板里写 <el-date-picker>,import 时写什么? |
import { ElDatePicker } from 'element-plus'。 |
| 忘了引入样式会怎样? | 组件能渲染,但没有组件库的样式。 |
ElConfigProvider 一般放在哪? |
放在最外层,包住整个页面。 |
| 中文项目需要单独配语言包吗? | 需要。默认是英文,中文界面里的“Total”就是没配的表现。 |
| 怎么知道一个组件有哪些属性? | 打开官方文档对应页面,看 API 表格里的 Attributes / Events / Slots 三张表。 |
一分钟现场演示指南
- 演示查文档:从零开始,在官网找到一个没用过的组件,复制示例,改成自己要的样子。这一分钟比讲十句理论有用。
- 演示全局配置:切换尺寸,让整页明显变化;再切换语言,指出分页文字的变化。
- 演示就近优先:指出那个写了
size="large"的按钮为什么不跟着变。 - 收尾一句:“会用组件库,一半是会用文档;另一半是会看自己的 import 列表。”
交作业前最后检查
src/App.vue与练习记录.md已保存。- 用到的每个组件都在 import 列表里。
- 全局尺寸与语言两个切换都能生效。
- 三个反馈组件(Message / Notification / MessageBox)都能弹出。
- Console 无红色报错。
课后再做一个小对照
打开 node_modules/element-plus/package.json,看看它的版本号;再去官网把当前版本与你项目里的版本对一下。写下一句话:为什么升级组件库版本前要先看它的更新日志(提示:属性的默认值和小写细节可能变化)。
来源:本课自编 Vue 3 前端核心技能实训 · 语法依据 Vue 3.5 官方文档 · 组件依据 Element Plus 2.8 官方文档