第10章 UI组件库与工具
第28节 Element Plus使用
10.28.1 安装与按需导入
什么是Element Plus?
Element Plus是一套基于Vue 3的桌面端组件库,是Element UI的Vue 3版本。它提供了丰富的组件,包括表单、表格、弹窗、导航等,能够帮助开发者快速构建美观、功能完善的Web应用。
安装Element Plus
使用npm安装:
npm install element-plus使用yarn安装:
yarn add element-plus使用pnpm安装:
pnpm add element-plus完整导入
完整导入是最简单的使用方式,但是会导入所有组件,增加打包体积:
// main.js
import { createApp } from 'vue'
import ElementPlus from 'element-plus' // 导入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')按需导入
按需导入可以只导入需要使用的组件,减小打包体积。Element Plus支持使用Vite或Webpack的自动导入插件。
使用Vite插件
- 安装自动导入插件:
npm install -D unplugin-vue-components unplugin-auto-import- 配置Vite:
// vite.config.js
import { defineConfig } from 'vite'
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: [
AutoImport({
resolvers: [ElementPlusResolver()],
}),
Components({
resolvers: [ElementPlusResolver()],
}),
],
})- 在组件中直接使用组件,无需导入:
<template>
<div>
<el-button type="primary">主要按钮</el-button>
<el-input v-model="input" placeholder="请输入内容"></el-input>
</div>
</template>
<script setup>
import { ref } from 'vue'
const input = ref('')
</script>手动按需导入
如果不使用自动导入插件,也可以手动按需导入组件:
// main.js
import { createApp } from 'vue'
import { ElButton, ElInput } from 'element-plus' // 手动导入需要的组件
import 'element-plus/es/components/button/style/css' // 导入按钮样式
import 'element-plus/es/components/input/style/css' // 导入输入框样式
import App from './App.vue'
const app = createApp(App)
app.use(ElButton)
app.use(ElInput)
app.mount('#app')10.28.2 常用组件学习
布局容器
Element Plus提供了el-container、el-header、el-aside、el-main和el-footer组件来实现常见的页面布局:
<template>
<el-container style="height: 500px; border: 1px solid #eee;">
<el-aside width="200px" style="background-color: rgb(238, 241, 246);">
<el-menu :default-openeds="['1', '3']">
<el-sub-menu index="1">
<template #title>
<el-icon><el-icon-menu /></el-icon>
<span>导航一</span>
</template>
<el-menu-item-group>
<template #title>分组一</template>
<el-menu-item index="1-1">选项1</el-menu-item>
<el-menu-item index="1-2">选项2</el-menu-item>
</el-menu-item-group>
</el-sub-menu>
<el-sub-menu index="2">
<template #title>
<el-icon><el-icon-document /></el-icon>
<span>导航二</span>
</template>
<el-menu-item index="2-1">选项1</el-menu-item>
</el-sub-menu>
</el-menu>
</el-aside>
<el-container>
<el-header style="text-align: center; line-height: 60px; background-color: #b3c0d1;">
头部区域
</el-header>
<el-main>
<el-card>
<template #header>
<div class="card-header">
<span>卡片标题</span>
<el-button type="primary" size="small">操作按钮</el-button>
</div>
</template>
<div>卡片内容区域</div>
</el-card>
</el-main>
<el-footer style="text-align: center; background-color: #b3c0d1;">
底部区域
</el-footer>
</el-container>
</el-container>
</template>
<style scoped>
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
}
</style>表单组件
Element Plus提供了丰富的表单组件,如el-input、el-select、el-radio、el-checkbox等:
<template>
<el-form :model="ruleForm" :rules="rules" ref="ruleFormRef" label-width="100px" class="demo-ruleForm">
<el-form-item label="用户名" prop="name">
<el-input v-model="ruleForm.name" placeholder="请输入用户名"></el-input>
</el-form-item>
<el-form-item label="密码" prop="pass">
<el-input v-model="ruleForm.pass" type="password" placeholder="请输入密码" show-password></el-input>
</el-form-item>
<el-form-item label="确认密码" prop="checkPass">
<el-input v-model="ruleForm.checkPass" type="password" placeholder="请确认密码" show-password></el-input>
</el-form-item>
<el-form-item label="性别" prop="gender">
<el-radio-group v-model="ruleForm.gender">
<el-radio label="male">男</el-radio>
<el-radio label="female">女</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="爱好" prop="hobbies">
<el-checkbox-group v-model="ruleForm.hobbies">
<el-checkbox label="读书"></el-checkbox>
<el-checkbox label="运动"></el-checkbox>
<el-checkbox label="游戏"></el-checkbox>
<el-checkbox label="音乐"></el-checkbox>
</el-checkbox-group>
</el-form-item>
<el-form-item label="职业" prop="occupation">
<el-select v-model="ruleForm.occupation" placeholder="请选择职业">
<el-option label="学生" value="student"></el-option>
<el-option label="教师" value="teacher"></el-option>
<el-option label="工程师" value="engineer"></el-option>
<el-option label="其他" value="other"></el-option>
</el-select>
</el-form-item>
<el-form-item label="个人简介" prop="introduction">
<el-input
v-model="ruleForm.introduction"
type="textarea"
:rows="3"
placeholder="请输入个人简介"
></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitForm(ruleFormRef)">提交</el-button>
<el-button @click="resetForm(ruleFormRef)">重置</el-button>
</el-form-item>
</el-form>
</template>
<script setup>
import { ref, reactive } from 'vue'
const ruleFormRef = ref()
const ruleForm = reactive({
name: '',
pass: '',
checkPass: '',
gender: 'male',
hobbies: [],
occupation: '',
introduction: ''
})
const rules = reactive({
name: [
{ required: true, message: '请输入用户名', trigger: 'blur' },
{ min: 3, max: 10, message: '长度在 3 到 10 个字符', trigger: 'blur' }
],
pass: [
{ required: true, message: '请输入密码', trigger: 'blur' },
{ min: 6, max: 20, message: '长度在 6 到 20 个字符', trigger: 'blur' }
],
checkPass: [
{ required: true, message: '请确认密码', trigger: 'blur' },
{
validator: (rule, value, callback) => {
if (value !== ruleForm.pass) {
callback(new Error('两次输入密码不一致'))
} else {
callback()
}
},
trigger: 'blur'
}
],
hobbies: [
{ required: true, message: '请至少选择一个爱好', trigger: 'change' }
],
occupation: [
{ required: true, message: '请选择职业', trigger: 'change' }
]
})
const submitForm = (formEl) => {
if (!formEl) return
formEl.validate((valid) => {
if (valid) {
console.log('表单验证通过', ruleForm)
} else {
console.log('表单验证失败')
return false
}
})
}
const resetForm = (formEl) => {
if (!formEl) return
formEl.resetFields()
}
</script>
<style scoped>
.demo-ruleForm {
max-width: 600px;
}
</style>数据展示组件
Element Plus提供了表格、卡片、标签页等数据展示组件:
<template>
<el-card>
<template #header>
<div class="card-header">
<span>用户列表</span>
<el-button type="primary" size="small" @click="dialogVisible = true">添加用户</el-button>
</div>
</template>
<el-table :data="tableData" style="width: 100%" border>
<el-table-column prop="date" label="日期" width="180"></el-table-column>
<el-table-column prop="name" label="姓名" width="180"></el-table-column>
<el-table-column prop="address" label="地址"></el-table-column>
<el-table-column label="操作" width="200" fixed="right">
<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>
<div class="pagination-container">
<el-pagination
v-model:current-page="currentPage"
v-model:page-size="pageSize"
:page-sizes="[10, 20, 50, 100]"
layout="total, sizes, prev, pager, next, jumper"
:total="tableData.length"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
></el-pagination>
</div>
</el-card>
<!-- 对话框 -->
<el-dialog
v-model="dialogVisible"
title="添加用户"
width="500px"
>
<el-form :model="form" label-width="80px">
<el-form-item label="姓名">
<el-input v-model="form.name"></el-input>
</el-form-item>
<el-form-item label="日期">
<el-date-picker
v-model="form.date"
type="date"
placeholder="选择日期"
style="width: 100%"
></el-date-picker>
</el-form-item>
<el-form-item label="地址">
<el-input v-model="form.address" type="textarea"></el-input>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="dialogVisible = false">确定</el-button>
</span>
</template>
</el-dialog>
</template>
<script setup>
import { ref, reactive } from 'vue'
const dialogVisible = ref(false)
const currentPage = ref(1)
const pageSize = ref(10)
const form = reactive({
name: '',
date: '',
address: ''
})
const tableData = reactive([
{
date: '2023-01-01',
name: '张三',
address: '北京市朝阳区'
},
{
date: '2023-01-02',
name: '李四',
address: '上海市浦东新区'
},
{
date: '2023-01-03',
name: '王五',
address: '广州市天河区'
},
{
date: '2023-01-04',
name: '赵六',
address: '深圳市南山区'
}
])
const handleEdit = (row) => {
console.log('编辑', row)
}
const handleDelete = (row) => {
console.log('删除', row)
}
const handleSizeChange = (size) => {
console.log('每页条数变化:', size)
pageSize.value = size
}
const handleCurrentChange = (current) => {
console.log('当前页码变化:', current)
currentPage.value = current
}
</script>
<style scoped>
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
}
.pagination-container {
margin-top: 20px;
display: flex;
justify-content: flex-end;
}
</style>反馈组件
Element Plus提供了消息提示、对话框、加载动画等反馈组件:
<template>
<div class="demo-feedback">
<el-button type="primary" @click="showMessage">消息提示</el-button>
<el-button type="success" @click="showSuccess">成功提示</el-button>
<el-button type="warning" @click="showWarning">警告提示</el-button>
<el-button type="danger" @click="showError">错误提示</el-button>
<el-button @click="showLoading">显示加载</el-button>
<el-button @click="showConfirm">确认对话框</el-button>
<el-button @click="showPrompt">输入对话框</el-button>
</div>
</template>
<script setup>
import { ElMessage, ElLoading, ElMessageBox } from 'element-plus'
const showMessage = () => {
ElMessage('这是一条消息提示')
}
const showSuccess = () => {
ElMessage.success('操作成功')
}
const showWarning = () => {
ElMessage.warning('警告提示')
}
const showError = () => {
ElMessage.error('操作失败')
}
const showLoading = () => {
const loading = ElLoading.service({
lock: true,
text: '加载中...',
background: 'rgba(0, 0, 0, 0.7)'
})
// 模拟异步操作
setTimeout(() => {
loading.close()
}, 2000)
}
const showConfirm = () => {
ElMessageBox.confirm('确定要删除这条数据吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
})
.then(() => {
ElMessage.success('删除成功')
})
.catch(() => {
ElMessage.info('已取消删除')
})
}
const showPrompt = () => {
ElMessageBox.prompt('请输入您的邮箱', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
inputPattern: /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/,
inputErrorMessage: '邮箱格式不正确'
})
.then(({ value }) => {
ElMessage.success(`您输入的邮箱是: ${value}`)
})
.catch(() => {
ElMessage.info('已取消输入')
})
}
</script>
<style scoped>
.demo-feedback {
display: flex;
gap: 10px;
flex-wrap: wrap;
}
</style>10.28.3 主题定制与国际化
主题定制
Element Plus支持通过CSS变量或Sass变量来定制主题。
使用CSS变量
- 在项目中创建主题文件:
/* src/styles/element-plus-theme.css */
:root {
/* 主色 */
--el-color-primary: #409eff;
--el-color-primary-light-3: #79bbff;
--el-color-primary-light-5: #a0cfff;
--el-color-primary-light-7: #c6e2ff;
--el-color-primary-light-8: #d9ecff;
--el-color-primary-light-9: #ecf5ff;
--el-color-primary-dark-2: #337ecc;
/* 成功色 */
--el-color-success: #67c23a;
/* 警告色 */
--el-color-warning: #e6a23c;
/* 危险色 */
--el-color-danger: #f56c6c;
/* 信息色 */
--el-color-info: #909399;
}- 在
main.js中引入主题文件:
import './styles/element-plus-theme.css'
import ElementPlus from 'element-plus'
import App from './App.vue'
const app = createApp(App)
app.use(ElementPlus)
app.mount('#app')使用Sass变量
- 安装Sass:
npm install -D sass- 创建主题文件:
/* src/styles/element-plus-variables.scss */
@forward 'element-plus/theme-chalk/src/common/var.scss' with (
$colors: (
'primary': (
'base': #409eff,
),
'success': (
'base': #67c23a,
),
'warning': (
'base': #e6a23c,
),
'danger': (
'base': #f56c6c,
),
'info': (
'base': #909399,
),
)
);- 配置Vite:
// vite.config.js
import { defineConfig } from 'vite'
import path from 'path'
export default defineConfig({
css: {
preprocessorOptions: {
scss: {
additionalData: `@use "${path.resolve(__dirname, 'src/styles/element-plus-variables.scss')}" as *;`,
},
},
},
})国际化
Element Plus支持多语言,默认使用英文。我们可以配置为中文或其他语言。
全局配置
// main.js
import { createApp } from 'vue'
import ElementPlus from 'element-plus'
import zhCn from 'element-plus/dist/locale/zh-cn.mjs' // 导入中文语言包
import App from './App.vue'
const app = createApp(App)
app.use(ElementPlus, {
locale: zhCn // 配置中文语言
})
app.mount('#app')组件内配置
<template>
<div>
<el-pagination
v-model:current-page="currentPage"
v-model:page-size="pageSize"
:page-sizes="[10, 20, 50, 100]"
layout="total, sizes, prev, pager, next, jumper"
:total="1000"
:prev-text="$t('pagination.prev')"
:next-text="$t('pagination.next')"
:sizes-text="$t('pagination.sizes')"
:total-text="$t('pagination.total')"
:jump-text="$t('pagination.jump-to')"
></el-pagination>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { useI18n } from 'vue-i18n'
const { t } = useI18n()
const currentPage = ref(1)
const pageSize = ref(10)
</script>10.28.4 自定义组件开发
我们可以基于Element Plus的组件来开发自定义组件。
自定义搜索组件
<template>
<div class="custom-search">
<el-input
v-model="searchValue"
placeholder="请输入搜索内容"
clearable
@keyup.enter="handleSearch"
@clear="handleClear"
>
<template #append>
<el-button type="primary" @click="handleSearch">
<el-icon><el-icon-search /></el-icon>
搜索
</el-button>
</template>
</el-input>
</div>
</template>
<script setup>
import { ref, watch } from 'vue'
const props = defineProps({
modelValue: {
type: String,
default: ''
},
placeholder: {
type: String,
default: '请输入搜索内容'
}
})
const emit = defineEmits(['update:modelValue', 'search', 'clear'])
const searchValue = ref(props.modelValue)
// 监听外部modelValue变化
watch(
() => props.modelValue,
(newVal) => {
searchValue.value = newVal
}
)
// 监听内部搜索值变化
watch(
searchValue,
(newVal) => {
emit('update:modelValue', newVal)
}
)
const handleSearch = () => {
emit('search', searchValue.value)
}
const handleClear = () => {
emit('clear')
}
</script>
<style scoped>
.custom-search {
width: 100%;
max-width: 400px;
}
</style>在父组件中使用:
<template>
<div>
<custom-search
v-model="searchText"
placeholder="搜索用户"
@search="onSearch"
@clear="onClear"
></custom-search>
<div class="search-result">
<p>搜索内容: {{ searchText }}</p>
<p>搜索结果: {{ searchResult }}</p>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
import CustomSearch from './CustomSearch.vue'
const searchText = ref('')
const searchResult = ref('')
const onSearch = (value) => {
searchResult.value = `搜索了: ${value}`
console.log('搜索:', value)
}
const onClear = () => {
searchResult.value = ''
console.log('清除搜索')
}
</script>
<style scoped>
.search-result {
margin-top: 20px;
padding: 10px;
border: 1px solid #eee;
border-radius: 4px;
}
</style>最佳实践与注意事项
按需导入:
- 使用自动导入插件可以简化开发,同时减小打包体积
- 对于小型项目,可以考虑完整导入以简化配置
主题定制:
- 使用CSS变量进行主题定制更简单,适合大多数项目
- 对于复杂的主题定制,可以使用Sass变量
组件使用:
- 熟悉Element Plus的组件API,合理选择组件
- 注意组件的事件和属性,避免不必要的性能开销
- 合理使用插槽来自定义组件内容
表单验证:
- 使用Element Plus的表单验证规则,提高表单的易用性
- 对于复杂的表单验证,使用自定义验证函数
国际化:
- 对于需要支持多语言的项目,使用国际化配置
- 合理使用i18n插件来管理翻译
性能优化:
- 对于大型列表,使用虚拟滚动
- 合理使用缓存和懒加载
- 避免在模板中使用复杂的计算逻辑
小结
本节我们学习了Element Plus的使用,包括:
- Element Plus的安装与按需导入
- 常用组件的使用:布局、表单、数据展示、反馈组件
- 主题定制与国际化
- 自定义组件开发
Element Plus是一个功能丰富、易于使用的Vue 3组件库,能够帮助我们快速构建美观、功能完善的Web应用。通过合理使用Element Plus的组件和功能,我们可以提高开发效率,同时保证代码的质量和可维护性。
思考与练习
- 安装Element Plus并配置按需导入。
- 使用Element Plus的布局组件创建一个页面布局。
- 创建一个包含表单验证的表单组件。
- 使用表格组件展示数据,并实现分页功能。
- 尝试定制Element Plus的主题颜色。
- 基于Element Plus组件开发一个自定义组件。