Vue.js: UI 组件库集成
最后更新:2026-08-26
UI 组件库能让你避免重复造轮子——Button / Table / Form / Modal 等常见组件,几行代码就能用。Vue 3 生态有 5+ 主流 UI 库(Element Plus / Naive UI / Vuetify / PrimeVue / Ant Design Vue),选对能省 50% 开发时间。
选 UI 库要考虑 5 大维度:组件丰富度 / TypeScript 支持 / 主题定制 / 包大小 / 社区活跃度。本课帮你做出正确选择。
1. 你将学到
- 5 大 Vue 3 UI 库对比(Element Plus / Naive UI / Vuetify / PrimeVue / Ant Design Vue)
- 按需引入(unplugin-vue-components)
- 主题定制(CSS 变量 / SCSS 变量)
- 组件二次封装(业务定制)
- Icon 库集成(@iconify / unplugin-icons)
- 5 个常见错误
2. 一个"5 个表格"组件重复 5 次的噩梦
(1) 痛点:每个表格都从零写
Alice 的后台有 5 个不同的表格视图,每个都是从零写起:
VUE
<!-- ❌ 翻车版:5 个表格,5 份不同代码 -->
<!-- OrdersTable.vue -->
<template>
<table>
<thead><tr><th>ID</th><th>User</th><th>Total</th></tr></thead>
<tbody>
<tr v-for="order in orders" :key="order.id">
<td>{{ order.id }}</td>
<td>{{ order.user }}</td>
<td>${{ order.total }}</td>
</tr>
</tbody>
</table>
</template>
<!-- ProductsTable.vue - 类似 -->
<!-- UsersTable.vue - 类似 -->
<!-- ... 还有 3 个 ... -->
5 个表格 × 200 行 = 1000 行重复代码。每改 1 个样式要改 5 处。
(2) UI 组件库解法:1 个 el-table,5 处复用
VUE
<!-- ✅ 正确版:用 Element Plus 的 el-table -->
<template>
<el-table :data="orders" stripe>
<el-table-column prop="id" label="ID" width="80" />
<el-table-column prop="user" label="User" />
<el-table-column prop="total" label="Total" :formatter="formatTotal" />
</el-table>
</template>
<script setup>
import { ElTable, ElTableColumn } from 'element-plus'
const orders = ref([...])
function formatTotal(row) { return `$${row.total}` }
</script>
1 个 el-table,5 处复用。所有表格样式统一、交互一致。
(3) 收益
使用 Element Plus 后:
- 代码量:1000 行 → 200 行(-80%)
- 样式一致性:100% 统一
- 新增表格:1 行模板
- TypeScript:完整类型推断
- 可访问性:内置 a11y
3. 5 大 Vue 3 UI 库对比
(1) 5 大库速查
| 库 | 风格 | 组件数 | 包大小 | TypeScript | 适用 |
|---|---|---|---|---|---|
| Element Plus | 桌面端 | 80+ | ~250KB | ✅ | 国内最流行、中后台 |
| Naive UI | 桌面端 | 80+ | ~150KB | ✅ | 现代风格、Vue 3 优先 |
| Vuetify | Material | 80+ | ~300KB | ✅ | Material Design 应用 |
| PrimeVue | 多风格 | 90+ | ~200KB | ✅ | 主题多、组件全 |
| Ant Design Vue | Ant Design | 70+ | ~180KB | ✅ | 蚂蚁风格、企业级 |
(2) 5 大维度详细对比
| 维度 | Element Plus | Naive UI | Vuetify | PrimeVue | Ant Design Vue |
|---|---|---|---|---|---|
| GitHub ⭐ | 24k+ | 16k+ | 40k+ | 11k+ | 20k+ |
| Vue 3 一等公民 | ✅ | ✅ | ✅ | ✅ | ✅ |
| TypeScript | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ |
| 主题定制 | CSS 变量 | CSS 变量 | SCSS | SCSS + 主题 | less + 主题 |
| 包大小 | 中 | 小 | 大 | 中 | 中 |
| 中文文档 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐ |
| 社区活跃 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐ |
| 学习曲线 | 平缓 | 平缓 | 中 | 中 | 中 |
(3) 5 大选择建议
| 场景 | 推荐 |
|---|---|
| 国内中后台(电商/CRM/ERP) | Element Plus ⭐⭐⭐⭐⭐ |
| 现代风格 SaaS | Naive UI ⭐⭐⭐⭐ |
| Material Design 应用 | Vuetify ⭐⭐⭐⭐ |
| 多主题(暗色/亮色/高对比度) | PrimeVue ⭐⭐⭐⭐ |
| Ant Design 生态 | Ant Design Vue ⭐⭐⭐⭐ |
4. Element Plus 实战
(1) 安装
BASH
npm install element-plus @element-plus/icons-vue
(2) 全局注册(简单)
JS
// main.js
const { createApp } = Vue
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
import App from './App.vue'
const app = createApp(App)
app.use(ElementPlus)
// 注册所有图标
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
app.component(key, component)
}
app.mount('#app')
(3) 按需引入(推荐,节省 50% 体积)
BASH
npm install -D unplugin-vue-components unplugin-auto-import
TS
// vite.config.ts
import AutoImport from 'unplugin-auto-import'
import Components from 'unplugin-vue-components'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
export default defineConfig({
plugins: [
AutoImport({
resolvers: [ElementPlusResolver()],
dts: 'src/auto-imports.d.ts'
}),
Components({
resolvers: [ElementPlusResolver()],
dts: 'src/components.d.ts'
})
]
})
VUE
<!-- ✅ 无需 import,自动按需引入 -->
<template>
<el-button>Click</el-button>
<el-input v-model="search" />
<el-table :data="list">
<el-table-column prop="name" label="Name" />
</el-table>
</template>
(4) 5 大核心组件
VUE
<template>
<!-- 1. Button -->
<el-button type="primary" @click="onClick">Primary</el-button>
<!-- 2. Form -->
<el-form :model="form" :rules="rules" ref="formRef">
<el-form-item label="Name" prop="name">
<el-input v-model="form.name" />
</el-form-item>
</el-form>
<!-- 3. Table -->
<el-table :data="list" stripe>
<el-table-column prop="name" label="Name" />
</el-table>
<!-- 4. Dialog -->
<el-dialog v-model="visible" title="Edit">
<p>Content</p>
</el-dialog>
<!-- 5. Message -->
<el-button @click="$message.success('Saved!')">Click</el-button>
</template>
5. 主题定制
(1) CSS 变量覆盖(推荐)
SCSS
// src/styles/element-plus.scss
:root {
--el-color-primary: #42b883; // 主色改为 Vue 绿
--el-color-success: #67c23a;
--el-color-warning: #e6a23c;
--el-color-danger: #f56c6c;
--el-color-info: #909399;
--el-border-radius-base: 8px; // 圆角加大
--el-font-size-base: 14px;
}
JS
// main.js
import './styles/element-plus.scss'
import 'element-plus/dist/index.css'
(2) SCSS 变量(深度定制)
SCSS
// src/styles/element-plus-vars.scss
@forward 'element-plus/theme-chalk/src/common/var.scss' with (
$colors: (
'primary': ('base': #42b883),
'success': ('base': #67c23a),
'warning': ('base': #e6a23c),
'danger': ('base': #f56c6c),
'info': ('base': #909399)
)
);
JS
// main.js
import './styles/element-plus-vars.scss'
import 'element-plus/dist/index.css'
(3) 暗色模式
SCSS
// 暗色主题
:root {
--el-color-primary: #42b883;
--el-bg-color: #1a1a1a;
--el-text-color-primary: #ffffff;
}
html.dark {
--el-bg-color: #1a1a1a;
--el-text-color-primary: #ffffff;
}
6. 组件二次封装
(1) 业务组件示例
VUE
<!-- components/BusinessTable.vue -->
<template>
<el-table
:data="data"
v-loading="loading"
stripe
border
:max-height="maxHeight"
>
<el-table-column type="index" label="#" width="60" />
<el-table-column
v-for="col in columns"
:key="col.key"
:prop="col.key"
:label="col.label"
:width="col.width"
:formatter="col.formatter"
/>
</el-table>
<el-pagination
v-model:current-page="page"
v-model:page-size="size"
:total="total"
:page-sizes="[10, 20, 50, 100]"
layout="total, sizes, prev, pager, next"
@current-change="onPage"
@size-change="onSize"
/>
</template>
<script setup lang="ts">
// 业务封装:自动 loading + 分页 + 列定义
const props = defineProps<{
data: any[]
columns: Array<{ key: string; label: string; width?: number; formatter?: Function }>
total: number
loading?: boolean
maxHeight?: number
}>()
const emit = defineEmits<{
'update:page': [page: number]
'update:size': [size: number]
}>()
const page = ref(1)
const size = ref(20)
function onPage(p) { emit('update:page', p) }
function onSize(s) { emit('update:size', s) }
</script>
VUE
<!-- 使用:3 行搞定 1 个表格 -->
<BusinessTable :data="orders" :columns="orderColumns" :total="100" />
(2) 5 大封装好处
- 减少重复代码: 50+ 表格共享
- 统一风格: 全部表格样式一致
- 业务定制: 自动 loading + 分页 + 空状态
- TypeScript: 强类型 props
- 可维护: 改 1 处生效 N 处
7. Icon 库集成
(1) 安装
BASH
npm install -D unplugin-icons @iconify-json/carbon
(2) 配置
TS
// vite.config.ts
import Icons from 'unplugin-icons/vite'
import { FileSystemIconLoader } from 'unplugin-icons/dist/loader'
export default defineConfig({
plugins: [
Icons({
compiler: 'vue3',
autoInstall: true, // 自动安装图标集
collections: {
carbon: () => import('@iconify-json/carbon/icons.json').then(i => i.default)
}
})
]
})
(3) 使用
VUE
<template>
<!-- Carbon 图标(10万+ 个) -->
<IconCarbonUser size="20" />
<IconCarbonShoppingCart size="24" color="green" />
<IconCarbonTrashCan size="20" @click="delete" />
</template>
(4) 5 大 Icon 库对比
| 库 | 图标数 | 加载方式 | 包大小 |
|---|---|---|---|
| Iconify | 200,000+ | 按需(推荐) | 0 |
| Element Icons | 300+ | 全部 / 按需 | 100KB |
| Material Icons | 2,000+ | 全部 / 按需 | 300KB |
| Font Awesome | 7,000+ | 全部 | 1MB+ |
| Heroicons | 300+ | 按需 | 50KB |
8. 完整示例:5 大 UI 库场景
▶ 示例:5 大 UI 库对比(⚠️ 需 Vite + npm install)
| 库 | ⭐ | 包大小 | 风格 |
|---|---|---|---|
| Element Plus | 24k | 中 | 桌面端 |
| Naive UI | 16k | 小 | 现代 |
| Vuetify | 40k | 大 | Material |
| PrimeVue | 11k | 中 | 多风格 |
| Ant Design Vue | 20k | 中 | Ant Design |
▶ 示例:5 大核心组件(以 Element Plus 为例)
VUE
<!-- 需 Vite + npm install element-plus -->
<el-button>Button</el-button>
<el-form>Form</el-form>
<el-table>Table</el-table>
<el-dialog>Dialog</el-dialog>
<el-message>Message</el-message>
▶ 示例:5 大主题定制
SCSS
/* 1. CSS 变量(推荐) */
:root { --el-color-primary: #42b883; }
/* 2. SCSS 变量(深度定制) */
@forward 'var.scss' with ($colors: ...);
/* 3. 暗色模式 */
:root.dark { --el-bg-color: #1a1a1a; }
/* 4. 自定义主题 */
@import 'element-plus/theme-chalk/dark/css-vars.css';
/* 5. 运行时切换 */
document.documentElement.classList.toggle('dark')
▶ 示例:5 大 Icon 库
| 库 | 图标数 |
|---|---|
| Iconify | 200,000+ |
| Element Icons | 300+ |
| Material | 2,000+ |
| Font Awesome | 7,000+ |
| Heroicons | 300+ |
▶ 示例:5 个常见错误速查
| 错误 | 现象 | 解决 |
|---|---|---|
| 全量引入包大 | bundle 500KB | 用 unplugin-vue-components 按需 |
| 主题色改不动 | 用了 SCSS | 改用 CSS 变量 |
| 图标不显示 | 字体加载失败 | 用 unplugin-icons SVG |
| TS 类型错误 | import 缺类型 | 装 @types 包 |
| 国际化失效 | locale 错 | 配 i18n |
❓ 常见问题
Q 5 大 UI 库选哪个?
A 国内中后台 → Element Plus(最流行)。现代 SaaS → Naive UI(小而美)。Material 应用 → Vuetify。Ant Design 生态 → Ant Design Vue。
Q 全量引入 vs 按需引入?
A 全量简单但 bundle 大(500KB)。按需推荐(unplugin-vue-components),节省 50% 体积。
Q 怎么改 Element Plus 主题色?
A 覆盖 CSS 变量
--el-color-primary。SCSS 变量定制需用 unplugin-element-plus 主题编译。Q Element Plus + TypeScript 完整支持吗?
A 是。Element Plus 2.x 完全 TypeScript 重写,类型推断完整。
Q UI 库能混用吗(如 Element Plus + Naive UI)?
A 技术上可以,但样式冲突难调。不推荐混用,选 1 个主库 + 1 个轻量库(如 Element Plus + Headless UI)。
Q unplugin-vue-components vs 全局注册?
A unplugin 自动按需引入,bundle 小 50%。全局简单但 bundle 大。推荐按需。
Q Icon 库怎么选?
A Iconify(200,000+ 跨多套)+ unplugin-icons 按需。零运行时开销。
📖 小节
- 5 大 Vue 3 UI 库:Element Plus / Naive UI / Vuetify / PrimeVue / Ant Design Vue
- Element Plus 国内最流行,组件丰富(80+)+ TypeScript
- 按需引入:unplugin-vue-components + ElementPlusResolver
- 主题定制:CSS 变量覆盖(推荐)+ SCSS 变量(深度)
- 二次封装:业务组件减少重复代码
- Iconify 200,000+ 图标 + unplugin-icons 按需
- 5 大 Icon 库:Iconify / Element / Material / Font Awesome / Heroicons
📝 作业
-
基础题(难度⭐) 集成 Element Plus 到 Vue 3 项目:
- 安装 + 按需引入
- 5 个核心组件(Button / Form / Table / Dialog / Message)
- 主题色改为项目主色
-
进阶题(难度⭐⭐) 实现完整的 Element Plus 集成:
- 5 大组件全用(Button / Form / Table / Dialog / Message)
- 暗色模式切换
- Iconify 图标(10 个不同图标)
- 二次封装 BusinessTable 组件
-
挑战题(难度⭐⭐⭐) 实现完整的"企业级 UI 库集成":
- Element Plus + Naive UI 混用(主 + 辅)
- 5 大主题色(主色 / 辅色 / 成功 / 警告 / 危险)
- 暗色模式 + 自动跟随系统
- 10+ 二次封装业务组件
- Iconify 200,000+ 图标
- TypeScript 强类型
- 性能优化(按需 + 树摇 + CDN)