Vue 组件库速查手册

基于 Vue 3 + Vite + <script setup>。涵盖 Element Plus / Naive UI / Ant Design Vue / Vuetify 3 常用场景。

0. 基础工程配置(通用)

# 创建项目(Node 16+)
npm create vite@latest my-app -- --template vue-ts
cd my-app && npm i

# 自动按需导入(强烈推荐)
npm i -D unplugin-auto-import unplugin-vue-components

vite.config.ts(基础)

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'

export default defineConfig({
  plugins: [
    vue(),
    AutoImport({
      imports: ['vue', 'vue-router', 'pinia'],
      dts: 'src/auto-imports.d.ts'
    }),
    Components({ dts: 'src/components.d.ts' })
  ]
})

main.ts(通用)

import { createApp } from 'vue'
import App from './App.vue'
const app = createApp(App)
app.mount('#app')

1. Element Plus(企业后台常用)

安装与按需引入

npm i element-plus @element-plus/icons-vue

自动导入(推荐)

// vite.config.ts
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
Components({
  resolvers: [ElementPlusResolver()],
})

手动全量(不推荐生产)

// main.ts
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
app.use(ElementPlus)

快速用法

<template>
  <el-button type="primary" @click="open = true">打开</el-button>
  <el-dialog v-model="open" title="对话框">
    <el-form :model="form" :rules="rules" ref="formRef" label-width="80px">
      <el-form-item label="姓名" prop="name"><el-input v-model="form.name"/></el-form-item>
      <el-form-item label="年龄" prop="age"><el-input-number v-model="form.age" :min="0"/></el-form-item>
    </el-form>
    <template #footer>
      <el-button @click="open=false">取消</el-button>
      <el-button type="primary" @click="submit">提交</el-button>
    </template>
  </el-dialog>
</template>
<script setup lang="ts">
import { ref } from 'vue'
const open = ref(false)
const formRef = ref()
const form = ref({ name: '', age: 18 })
const rules = { name: [{ required: true, message: '必填', trigger: 'blur' }] }
const submit = () => formRef.value?.validate((ok: boolean)=> ok && (open.value=false))
</script>

主题与暗色

  • 引入基础样式后,可用 class="dark" + CSS 变量启用暗色方案(需引入 element-plus/theme-chalk/dark/css-vars.css)。
import 'element-plus/theme-chalk/dark/css-vars.css'

图标

import * as ElIcons from '@element-plus/icons-vue'
Object.entries(ElIcons).forEach(([k, c]) => app.component(k, c as any))

2. Naive UI(风格轻盈、默认按需)

安装

npm i naive-ui @css-render/vue3-ssr # ssr 可选

快速用法

<template>
  <n-config-provider :theme="dark ? darkTheme : null">
    <n-space>
      <n-button type="primary" @click="show=true">Open</n-button>
      <n-switch v-model:value="dark">Dark</n-switch>
    </n-space>
    <n-modal v-model:show="show" preset="dialog" title="提示" content="操作完成"/>
    <n-form :model="form" :rules="rules" ref="formRef">
      <n-form-item label="邮箱" path="email"><n-input v-model:value="form.email"/></n-form-item>
    </n-form>
  </n-config-provider>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { darkTheme } from 'naive-ui'
const dark = ref(false)
const show = ref(false)
const formRef = ref()
const form = ref({ email: '' })
const rules = { email: [{ required: true, message: '必填' }] }
</script>

自动导入(可选)

// vite.config.ts
import { NaiveUiResolver } from 'unplugin-vue-components/resolvers'
Components({ resolvers: [NaiveUiResolver()] })

图标

  • 推荐 @vicons/* 套件(例如 @vicons/ionicons5),与 <n-icon> 搭配:
<n-icon><HomeOutline/></n-icon>

3. Ant Design Vue(中后台 + 设计规范)

安装

npm i ant-design-vue @ant-design/icons-vue

引入方式

// 全量(简单但体积大)
import Antd from 'ant-design-vue'
import 'ant-design-vue/dist/reset.css'
app.use(Antd)

// 按需(推荐)
import { Button, Modal, Form, Input } from 'ant-design-vue'
app.use(Button).use(Modal).use(Form).use(Input)

快速用法

<template>
  <a-space>
    <a-button type="primary" @click="open=true">Open</a-button>
    <a-button danger @click="count++">Count: {{ count }}</a-button>
  </a-space>
  <a-modal v-model:open="open" title="标题">
    <a-form :model="form" :rules="rules" ref="formRef" layout="vertical">
      <a-form-item label="姓名" name="name" :rules="[{ required: true, message: '必填' }]">
        <a-input v-model:value="form.name"/>
      </a-form-item>
    </a-form>
  </a-modal>
</template>
<script setup lang="ts">
import { ref } from 'vue'
const open = ref(false)
const count = ref(0)
const formRef = ref()
const form = ref({ name: '' })
const rules = { }
</script>

主题定制(令牌 Token)

  • 可通过 <a-config-provider :theme="{ token: { colorPrimary: '#1677ff' } }"> 在应用层定制主色等 Token。

图标

import * as Icons from '@ant-design/icons-vue'
Object.entries(Icons).forEach(([k, c]) => app.component(k, c as any))

4. Vuetify 3(Material Design)

安装

npm i vuetify @mdi/font # @mdi/font 提供图标字体

main.ts 配置

import { createApp } from 'vue'
import App from './App.vue'
import 'vuetify/styles'
import { createVuetify } from 'vuetify'
import * as components from 'vuetify/components'
import * as directives from 'vuetify/directives'

const vuetify = createVuetify({ components, directives })
createApp(App).use(vuetify).mount('#app')

快速用法

<template>
  <v-app>
    <v-container>
      <v-btn @click="dialog=true">Open</v-btn>
      <v-dialog v-model="dialog" max-width="420">
        <v-card>
          <v-card-title>标题</v-card-title>
          <v-card-text>
            <v-form ref="formRef" v-model="valid">
              <v-text-field v-model="name" label="姓名" :rules="[v=>!!v||'必填']"/>
            </v-form>
          </v-card-text>
          <v-card-actions>
            <v-spacer/>
            <v-btn text @click="dialog=false">取消</v-btn>
            <v-btn color="primary" :disabled="!valid" @click="dialog=false">提交</v-btn>
          </v-card-actions>
        </v-card>
      </v-dialog>
    </v-container>
  </v-app>
</template>
<script setup lang="ts">
import { ref } from 'vue'
const dialog = ref(false)
const name = ref('')
const valid = ref(false)
</script>

主题与暗色

const vuetify = createVuetify({
  theme: {
    defaultTheme: 'light',
    themes: {
      light: { colors: { primary: '#1867C0' } },
      dark: { dark: true }
    }
  }
})

5. 自动按需导入(整合示例)

// vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver, NaiveUiResolver, AntDesignVueResolver } from 'unplugin-vue-components/resolvers'

export default defineConfig({
  plugins: [
    vue(),
    AutoImport({ imports: ['vue'], dts: 'src/auto-imports.d.ts' }),
    Components({
      dts: 'src/components.d.ts',
      resolvers: [
        ElementPlusResolver(),
        NaiveUiResolver(),
        AntDesignVueResolver({ importStyle: false })
      ]
    })
  ]
})
注:Vuetify 以官方注册方式为主,通常不走 resolver(也可单独配置社区 resolver)。

6. 表单校验策略对比

  • Element Plus<el-form> + rules,字段级 triggerblur/change)。
  • Naive UI<n-form> + rules,支持异步校验、path 指定字段。
  • Ant Design Vue<a-form> + rulesname 层级规则,v-model:value
  • Vuetify<v-form v-model="valid"> + 各输入组件 :rules="[(v)=>true||'msg']"

如需复杂 Schema,统一接入 zod/yup

import { z } from 'zod'
const schema = z.object({ email: z.string().email() })

7. 国际化与布局

  • 国际化:四者均可与 vue-i18n 搭配;Element Plus/AntD 提供内置 Locale 组件。
  • 布局:AntD <a-layout>、Vuetify <v-layout>、Element <el-container>,Naive UI 以 n-layout/n-layout-sider 组合为主。
npm i vue-i18n

8. 性能与体积小贴士

  • 强制按需(避免全量引入)。
  • 生产构建使用 vite build --report 分析体积(或 rollup-plugin-visualizer)。
  • 图片与图标优先 SVG(Ant/Element/N-UI 均支持自定义图标组件)。
  • 大型表格虚拟滚动:优先选库内置表格优化(或 vue-virtual-scroller)。

9. 迁移与选型建议

  • 数据录入密集 + 稳健:Element Plus / Ant Design Vue
  • 设计统一 + Material:Vuetify
  • 极简风格 + 轻量主题:Naive UI
  • 海外移动端 + PWA:可评估 Quasar(未在本文详述)。

10. 常用样板片段(可复制)

顶栏 + 侧边栏布局(AntD 版本)

<template>
  <a-layout style="min-height: 100vh">
    <a-layout-sider collapsible v-model:collapsed="collapsed">
      <div class="logo">My Admin</div>
      <a-menu theme="dark" mode="inline" :items="items" />
    </a-layout-sider>
    <a-layout>
      <a-layout-header style="background:transparent">
        <a-space>
          <a-button type="text" @click="collapsed=!collapsed">Toggle</a-button>
        </a-space>
      </a-layout-header>
      <a-layout-content style="margin:16px">
        <RouterView />
      </a-layout-content>
    </a-layout>
  </a-layout>
</template>
<script setup lang="ts">
import { ref } from 'vue'
const collapsed = ref(false)
const items = [
  { key: '1', label: '首页' },
  { key: '2', label: '用户' }
]
</script>

过滤表格(Element Plus 版本)

<template>
  <el-space direction="vertical" style="width:100%">
    <el-input v-model="q" placeholder="搜索..." clearable />
    <el-table :data="rows.filter(r=>r.name.includes(q))" height="420">
      <el-table-column prop="name" label="姓名"/>
      <el-table-column prop="age"  label="年龄"/>
      <el-table-column label="操作">
        <template #default="{ row }">
          <el-button size="small" @click="edit(row)">编辑</el-button>
        </template>
      </el-table-column>
    </el-table>
  </el-space>
</template>
<script setup lang="ts">
import { ref } from 'vue'
const q = ref('')
const rows = ref([{name:'Ada',age:28},{name:'Alan',age:35}])
const edit = (r:any)=> console.log(r)
</script>

暗色切换(Naive UI 版本)

<template>
  <n-config-provider :theme="dark?darkTheme:null">
    <n-space align="center">
      <n-switch v-model:value="dark">Dark</n-switch>
      <n-button>Primary</n-button>
    </n-space>
  </n-config-provider>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { darkTheme } from 'naive-ui'
const dark = ref(false)
</script>

登录卡片(Vuetify 版本)

<template>
  <v-container class="d-flex align-center" style="min-height:100vh">
    <v-card width="420">
      <v-card-title>登录</v-card-title>
      <v-card-text>
        <v-text-field label="邮箱" v-model="email" type="email"/>
        <v-text-field label="密码" v-model="pwd" type="password"/>
      </v-card-text>
      <v-card-actions>
        <v-spacer/>
        <v-btn color="primary" @click="login">登录</v-btn>
      </v-card-actions>
    </v-card>
  </v-container>
</template>
<script setup lang="ts">
import { ref } from 'vue'
const email = ref(''); const pwd = ref('')
const login = ()=>{/* 调用 API */}
</script>

添加新评论