设计
- 控制反馈: 通过界面样式和交互动效让用户可以清晰的感知自己的操作;
- 页面反馈: 操作后,通过页面元素的变化清晰地展现当前状态。
- 帮助用户识别: 界面简单直白,让用户快速识别而非回忆,减少用户记忆负担。
- 用户决策: 根据场景可给予用户操作建议或安全提示,但不能代替用户进行决策;
- 结果可控: 用户可以自由的进行操作,包括撤销、回退和终止当前操作等。
安装
- Element Plus 可以在支持 ES2018 和 ResizeObserver 的浏览器上运行。
- 直接通过浏览器的 HTML 标签导入 Element Plus,然后就可以使用全局变量 ElementPlus
- 根据不同的 CDN 提供商有不同的引入方式
- 我们建议使用 CDN 引入 Element Plus 的用户在链接地址上锁定版本,以免将来 Element Plus 升级时受到非兼容性更新的影响。 锁定版本的方法请查看 unpkg.com
<head>
<!-- Import style -->
<link rel="stylesheet" href="//unpkg.com/element-plus/dist/index.css" />
<!-- Import Vue 3 -->
<script src="//unpkg.com/vue@3"></script>
<!-- Import component library -->
<script src="//unpkg.com/element-plus"></script>
</head>
快速开始
- 如果您使用 Volar,请在 tsconfig.json 中通过 compilerOptions.type 指定全局组件类型。
- 注释:compilerOptions.type 声明类型应该包括的文件夹
// tsconfig.json
{
"compilerOptions": {
// ...
"types": ["element-plus/global"]
}
}
- 按需导入
- 需要安装unplugin-vue-components 和 unplugin-auto-import这两款插件
- 注释:unplugin-vue-components 是一个用于自动按需引入 Vue 组件的插件,它支持 Vue 2 和 Vue 3,支持 Vite, Webpack, Rspack, Vue CLI, Rollup, esbuild 等构建工具,支持内置的解析器和自定义的解析器,支持 TypeScript 和 .d.ts 文件生成。它可以让您在模板中直接使用组件,而不需要手动导入和注册
- 注释:unplugin-auto-import 是一个用于自动按需引入 Vue, React, Pinia 等库的 API 的插件,它也支持多种构建工具和 TypeScript
- 注释:这两个插件都是基于 unplugin 这个框架开发的,unplugin 是一个用于创建通用的构建工具插件的框架
- 对于 Nuxt 用户,只需要安装 @element-plus/nuxt 即可
// nuxt.config.ts
export default defineNuxtConfig({
modules: ['@element-plus/nuxt'],
})
- Element Plus 提供了基于 ES Module 的开箱即用的 Tree Shaking 功能。
- 需要安装 unplugin-element-plus 来导入样式。
- 注释:unplugin-vue-components 和 unplugin-element-plus 都能支持按需导入,建议使用 unplugin-element-plus 就行
// vite.config.ts
import { defineConfig } from 'vite'
import ElementPlus from 'unplugin-element-plus/vite'
export default defineConfig({
// ...
plugins: [ElementPlus()],
})
- 引入 ElementPlus 时,可以传入一个包含 size 和 zIndex 属性的全局配置对象。 size 用于设置表单组件的默认尺寸,zIndex 用于设置弹出组件的层级,zIndex 的默认值为 2000。
import { createApp } from 'vue'
import ElementPlus from 'element-plus'
import App from './App.vue'
const app = createApp(App)
app.use(ElementPlus, { size: 'small', zIndex: 3000 })
<template>
<el-config-provider :size="size" :z-index="zIndex">
<app />
</el-config-provider>
</template>
<script>
import { defineComponent } from 'vue'
import { ElConfigProvider } from 'element-plus'
export default defineComponent({
components: {
ElConfigProvider,
},
setup() {
return {
zIndex: 3000,
size: 'small',
}
},
})
</script>
国际化
- 提供了一个 Vue 组件 ConfigProvider 用于全局配置国际化的设置
<template>
<el-config-provider :locale="locale">
<app />
</el-config-provider>
</template>
<script>
import { defineComponent } from 'vue'
import { ElConfigProvider } from 'element-plus'
import zhCn from 'element-plus/dist/locale/zh-cn.mjs'
export default defineComponent({
components: {
ElConfigProvider,
},
setup() {
return {
locale: zhCn,
}
},
})
</script>
- 我们使用 Day.js 库来管理组件的日期和时间,例如 DatePicker。 必须在 Day.js 中设置一个适当的区域,以便使国际化充分发挥作用。 您必须分开导入Day.js的区域设置。
- 注释:Day.js 对国际化支持良好。但除非手动加载,多国语言默认是不会被打包到工程里的
import 'dayjs/locale/zh-cn'
从 Element UI 升级
- 迁移
- 基于类名的 Font Icon 已被移除,这意味着您需要把所有 el-icon- 相关的代码迁移至 SVG Font
- 全局配置 Vue.prototype.$ELEMENT 已删除
- 各组件的变量使用 @use 'sass:map'; 进行组织,对应组件的变量移动至对应组件名称下。
// 一个名为$switch的变量,!default表示如果这个变量已经被定义过了
$switch: () !default;
// 使用map.merge函数,把$switch和默认值合并,得到一个新的map,赋值给 $switch
$switch: map.merge(
(
'on-color': var(--el-color-primary),
'off-color': var(--el-border-color-base),
'core-border-radius': 10px,
'width': 40px,
'height': 20px,
'button-size': 16px,
),
$switch
);
// 用户自定义变量:(将会自动覆盖并合并默认变量)
@forward 'element-plus/theme-chalk/src/common/var.scss' with (
// 设置主题色
$colors:
(
'primary': (
'base': green,
)
),
// 覆盖 switch 组件变量
$switch: ('height': 40px)
);
主题
- 注释:全局引入 element-plus 时会独取 package.json 中的 style 这个属性,自动加载它指向的样式文件
- 在 element-plus scss 文件之前导入element/index.scss以避免 sass 混合变量的问题,因为我们需要通过你的自定义变量生成 light-x。
- 创建一个 element/index.scss 文件来合并你的变量和 element-plus 的变量。 (如果你在 TypeScript 中导入了它们,他们将不会被合并)
- 注释:在 ts 中可以直接引用 sass 定义的变量
- 注释:
import './styles/element/index.scss'
只引用了变量文件,最后编译为 css 原生变量,覆盖import ElementPlus from 'element-plus'
引入样式中定义的 css 原生变量
import { createApp } from 'vue'
import './styles/element/index.scss'
import ElementPlus from 'element-plus'
import App from './App.vue'
const app = createApp(App)
app.use(ElementPlus)
- 应该将你的 scss 文件与 element 变量的 scss 文件区分开来。 如果将它们混合在一起,element-plus 每次热更新都需要编译大量的 scss 文件,这将会导致编译速度变慢。
- 如果你正在使用 vite,并且你想在按需导入时自定义主题。
- 使用 scss.additionalData 来编译所有应用 scss 变量的组件。
import path from 'path'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// 你也可以使用 unplugin-vue-components
// import Components from 'unplugin-vue-components/vite'
// import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
// 或者使用 unplugin-element-plus
import ElementPlus from 'unplugin-element-plus/vite'
// vite.config.ts
export default defineConfig({
resolve: {
alias: {
'~/': `${path.resolve(__dirname, 'src')}/`,
},
},
// css.preprocessorOptions.scss.additionalData 用来指定一些额外的数据,比如变量,函数,混合等,这些数据会被自动添加到每个scss文件的开头,这样就可以在scss文件中直接使用这些数据,而不需要重复地导入或定义它们
css: {
preprocessorOptions: {
scss: {
additionalData: `@use "~/styles/element/index.scss" as *;`,
},
},
},
plugins: [
vue(),
// use unplugin-vue-components
// Components({
// resolvers: [
// ElementPlusResolver({
// importStyle: "sass",
// // directives: true,
// // version: "2.1.5",
// }),
// ],
// }),
// 或者使用 unplugin-element-plus
ElementPlus({
// 是否使用element-plus的源码来按需引入组件和样式。
useSource: true,
}),
],
})
- 如果你只想自定义一个特定的组件,只需为某些组件单独添加内联样式。
<el-tag style="--el-tag-bg-color: red">Tag</el-tag>
- 出于性能原因,更加推荐你在类名下添加自定义 css 变量,而不是在全局的 :root 下
.custom-class {
--el-tag-bg-color: red;
}
暗黑模式
- 需要暗色模式,只需在 html 上添加一个名为 dark 的类
// main.ts
// 如果只想导入css变量
import 'element-plus/theme-chalk/dark/css-vars.css'
// html
<html class="dark">
<head></head>
<body></body>
</html>
// main.ts
import 'element-plus/theme-chalk/dark/css-vars.css'
import './styles/dark/css-vars.css'
// ./styles/dark/css-vars.css
html.dark {
/* 自定义深色背景颜色 */
--el-bg-color: #626aef;
}
// styles/element/index.scss
/* 覆盖你需要的变量 */
@forward 'element-plus/theme-chalk/src/dark/var.scss' with (
$bg-color: (
'page': #0a0a0a,
'': #626aef,
'overlay': #1d1e1f,
)
);
自定义命名空间
- Element Plus 提供的默认命名空间为 el。 在特殊情况下,我们需要自定义命名空间
- 必须同时设置 ElConfigProvider 和 scss $namespace
<!-- App.vue -->
<template>
<el-config-provider namespace="ep">
<!-- ... -->
</el-config-provider>
</template>
// styles/element/index.scss
// we can add this to custom namespace, default is 'el'
@forward 'element-plus/theme-chalk/src/mixins/config.scss' with (
$namespace: 'ep'
);
// ...
// vite.config.ts
import { defineConfig } from 'vite'
// https://vitejs.dev/config/
export default defineConfig({
// ...
css: {
preprocessorOptions: {
scss: {
additionalData: `@use "~/styles/element/index.scss" as *;`,
},
},
},
// ...
})
SSR
- 当使用 Element Plus 在 SSR 场景下开发时,您需要在 SSR 期间进行特殊处理,以避免水合错误。
- 注释:水合是指在服务端渲染(SSR)的过程中,客户端接收到服务端渲染的 HTML 片段后,重新创建组件树并将动态数据注入其中,使得组件树能够响应用户交互的过程
- 注释:水合错误是指在服务端渲染(SSR)的过程中,服务端渲染的 DOM 结构和浏览器端渲染的 DOM 结构不一致,导致两者无法正确地融合(水合)的错误
- 提供的值用于生成 ElementPlus 中的唯一ID。 因为不同的 IDs 容易发生SSR中的水合错误, 为了确保服务器端和客户端生成相同的ID, 我们需要将 ID_injection_key 注入到 Vue。
- 注释:如果没有提供ID_INJECTION_KEY,那么在客户端进行水合的时候,可能会出现两个相同的组件无法区分的问题
// src/main.js (irrelevant code omitted)
import { createApp } from 'vue'
import { ID_INJECTION_KEY } from 'element-plus'
import App from './App.vue'
const app = createApp(App)
app.provide(ID_INJECTION_KEY, {
prefix: 1024,
current: 0,
})
- Teleport 被元素加元件中的多个组件内部使用 (例如) ElDialog, ElDrawer, ElTooltip, ElDropdown, ElSelect, ElDatePicker ...),所以在SSR期间需要特殊处理。
- 注释:Teleport 传送组件
- 一个较容易的解决办法是有条件渲染挂载上的 Teleport 。
- 注释:Teleport 在挂载时才转移 dom 节点,水合时,js创建的 dom 和服务端的 dom 存在这个差别,导致水合错误。
- 注释:可以在通过 v-if 绑定状态,在挂载后改为 true,保证初始 dom 水合成功后才增加转移的占位 dom
- 注释:组件 v-if=false 不会触发挂载事件
- 另一种方式是将传送标记注入到你的 HTML 页面末尾的正确位置。
- 注释:他们被独立出来了,不会影响主体部分的水合
- 基于 ElTooltip 的 teleported 的属性应该是一致的,建议使用默认值。
- 注释:teleported 用来控制是否使用 append-to 属性,append-to默认值是 elemit-plus 添加在 body 下的一个 div,默认类似
<div id="el-popper-container-202"></div>
,部分元素的文档说明为 body,与事实不符
- ElDialog 和 ElDrawer 的 append-to-body 属性值应该是一致的,建议启用 append-to-body。
- ElSubMenu组件有多层弹出窗口,建议启用 popper-append-to-body
- 您需要注入靠近 <body> 标签的传送标记。(疑问)
<!DOCTYPE html>
<html lang="en">
<head>
<title>Element Plus</title>
<!--preload-links-->
</head>
<body>
<!--app-teleports-->
<div id="app"><!--app-html--></div>
<script type="module" src="/src/entry-client.js"></script>
</body>
</html>
- 如果您修改了 Namespace 或 append-to 属性,您需要调整 #el-popper-container- 值(略)
内置过渡动画
- 淡入淡出 el-fade-in-linear 和 el-fade-in 两种效果
- 缩放 el-zoom-in-center,el-zoom-in-top 和 el-zoom-in-bottom 三种效果
- 使用 el-collapse-transition 组件实现折叠展开效果
开发指南
- 注释:参与 element plus 的开发指南
- 本地开发指南
开发常见问题
- 链接本地依赖
- 注释:在其他项目跳时 element-plus 本地打包后的结果
# 获取构建结果
pnpm build
cd dist/element-plus
# set cur element-plus to global `node_modules`
pnpm link --global
# for esm we also need link element-plus for dist
pnpm link --global element-plus
# 进入你的项目, 链接到 `element-plus`
cd your-project
pnpm link --global element-plus
- 主题
- 不应在scss文件中写入中文注释
- 那将会在 vite 构建下的 css 文件开头生成警告信息 @charset "UTF-8";
提交示例(略)
翻译(略)
- 采用了 Crowdin 作为自动化的第一步来升级文档站
- 注释:Crowdin是一个基于云的本地化管理平台,它可以帮助你的团队高效地管理多语言内容
组件————————————————
Icon 图标
- 注释:每一个图标都被封装成独立的组件
- 使用 unplugin-icons 和 unplugin-auto-import 从 iconify 中自动导入任何图标集。
- 注释:unplugin-icons是一个可以动态生成图标组件的插件。
- 注释:生成的图标组件可以通过 unplugin-auto-import 自动导入
- 注释:Iconify 是一个开源的图标项目,它收集了一百多个高质量的图标库,包括 Ant Design、Bootstrap、Feather、Material Design 等。
- 注释:Iconify 提供了多种方式来引入和使用图标,如 Web Component、React Component、Vue Component 等。
- 通过添加额外的类名 is-loading,你的图标就可以在 2 秒内旋转 360 度
Config Provider 全局配置
<template>
<div>
<el-button mb-2 @click="toggle">Switch Language</el-button>
<br />
<el-config-provider :locale="locale">
<el-table mb-1 :data="[]" />
<el-pagination :total="100" />
</el-config-provider>
</div>
</template>
<script lang="ts" setup>
import { computed, ref } from 'vue'
import zhCn from 'element-plus/dist/locale/zh-cn.mjs'
import en from 'element-plus/dist/locale/en.mjs'
const language = ref('zh-cn')
const locale = computed(() => (language.value === 'zh-cn' ? zhCn : en))
const toggle = () => {
language.value = language.value === 'zh-cn' ? 'en' : 'zh-cn'
}
</script>
- 对消息进行配置
- 疑问:ElMessage 是如何获取正确的组件实例的
<template>
<div>
<el-config-provider :message="config">
<el-button @click="open">OPEN</el-button>
</el-config-provider>
</div>
</template>
<script lang="ts" setup>
import { reactive } from 'vue'
import { ElMessage } from 'element-plus'
const config = reactive({
max: 3,
})
const open = () => {
ElMessage('This is a message.')
}
</script>