@macroui/macroui-vue
v2.17.278
Published
基于 Vue 3 + MacroUI 兼容 Element Plus API 风格的组件库
Downloads
60,169
Maintainers
Readme
@macroui/macroui-vue
Vue 3 + Element Plus API + MacroUI 视觉风格的组件库
🎯 @macroui/macroui-vue 是基于 Vue 3(Composition API +
<script setup>)开发的 90+ 组件库,提供与 Element Plus 完全一致 的 API(组件名、props、events、slots),同时视觉层基于 @macroui/macroui(DaisyUI 风格)与 Tailwind CSS,覆盖 30+ 主题。
- 官方网站:https://github.com/mobiui/macroui
- API 兼容:100% Element Plus API(迁移零成本)
- 主题切换:
data-themeCSS 变量 - TypeScript:完整类型定义
- 多语言:67+ 语言内置
目录
- 1. 项目简介
- 2. 安装
- 3. 快速开始
- 4. 主题系统
- 5. 国际化 i18n
- 6. 全局配置 ElConfigProvider
- 7. 组件完整参考
- 8. 工具函数与 Hooks
- 9. 按需引入
- 10. SSR / Nuxt
- 11. 浏览器支持
- 12. 开发与构建
- 13. NPM 发布
- 14. 项目结构
- 15. 常见问题
- 16. 许可证
1. 项目简介
@macroui/macroui-vue 是 Element Plus API 风格 + MacroUI 视觉风格 的 Vue 3 组件库。
1.1 与 Element Plus 的关系
| 比较项 | Element Plus | macroui-vue |
|--------|--------------|-------------|
| API 兼容 | ✅ | ✅ 100% 兼容 |
| 主题方案 | CSS 变量 + SCSS | CSS 变量(DaisyUI) |
| 内置主题数 | 4 | 30+ |
| 主题切换 | 静态 SCSS | 运行时 data-theme |
| 样式覆盖 | SCSS 变量 | Tailwind class |
| 体积 | ~250KB | ~150KB |
| 多语言 | 55+ | 67+ |
迁移成本 = 0:只需替换 element-plus → @macroui/macroui-vue。
1.2 特性
- 🎨 30+ MacroUI 主题(light / dark / corporate / synthwave / cyberpunk / dracula ...)
- 📦 90+ 组件 — 表单、数据展示、反馈、容器、导航全覆盖
- 🧩 Element Plus 兼容 API —
el-button、el-table、el-form、el-input命名一致 - 🌐 多语言 (i18n) — 67 种语言内置,支持运行时切换
- 🛠 TypeScript 优先 — 完整类型定义
- ⚡ 按需引入 — 全量注册 / 具名导入皆可
- 🎯 Vue 3 Composition API — 完全基于
<script setup>风格开发 - 💡 Tailwind + DaisyUI — 可直接使用
btn btn-primary等 DaisyUI 类
1.3 适用项目
- 后台管理系统
- 中后台 CRUD 页面
- 数据可视化大屏
- 表单密集型应用
- 需要快速统一视觉风格的多端项目
2. 安装
2.1 通过 npm / pnpm / yarn 安装
# npm
npm install @macroui/macroui-vue @macroui/macroui @macroui/macroui-icons vue
# pnpm (推荐)
pnpm add @macroui/macroui-vue @macroui/macroui @macroui/macroui-icons vue
# yarn
yarn add @macroui/macroui-vue @macroui/macroui @macroui/macroui-icons vueVue 3 是 peerDependency,必须显式安装。
2.2 peerDependencies
| 包名 | 版本 |
|------|------|
| vue | >= 3.2.0(推荐 3.4+) |
2.3 dependencies
| 包名 | 版本 | 说明 |
|------|------|------|
| @macroui/macroui | ^4.3.0 | MacroUI 主题与样式 |
| @macroui/macroui-icons | ^2.1.0 | 图标库 |
| lodash-unified | ^1.0.3 | 工具函数(按需 tree-shake) |
2.4 可选 peerDependencies(按需引入时视使用组件而定)
@macroui/macroui-vue 在构建期将这些运行时依赖标记为 external,不会打包进 bundle,请按需安装:
| 包名 | 何时需要 |
|------|----------|
| @vueuse/core | Tooltip / Dropdown / 弹层类组件用到的基础 hook |
| @popperjs/core | el-tooltip、el-dropdown、el-popover 等 Popper 定位 |
| @floating-ui/dom | el-floating 工具与新定位算法 |
| lodash-unified | 通用工具函数 |
一键安装建议:
pnpm add @vueuse/core @popperjs/core @floating-ui/dom lodash-unified
3. 快速开始
3.1 完整注册(推荐)
// main.ts
import { createApp } from 'vue'
import App from './App.vue'
// 1. 加载 CSS(**顺序很重要**:先主题,再组件)
import '@macroui/macroui/dist/themes.css' // MacroUI 主题变量
import '@macroui/macroui/dist/styled.css' // MacroUI styled 组件类
import '@macroui/macroui-vue/dist/style.css' // Vue 组件覆盖样式
// 2. 导入组件与插件
import MacrouiVue from '@macroui/macroui-vue'
import { zhCn } from '@macroui/macroui-vue/locale'
// 3. 创建应用
const app = createApp(App)
// 4. 全局注册全部组件 + ElConfigProvider
app.use(MacrouiVue, { locale: zhCn })
// 5. 挂载
app.mount('#app')3.2 按需引入
// main.ts
import { createApp } from 'vue'
import {
ElButton,
ElInput,
ElTable,
ElTableColumn,
ElConfigProvider,
} from '@macroui/macroui-vue'
import { zhCn } from '@macroui/macroui-vue/locale'
import App from './App.vue'
import '@macroui/macroui/dist/themes.css'
import '@macroui/macroui/dist/styled.css'
import '@macroui/macroui-vue/dist/style.css'
const app = createApp(App)
app.use(ElButton)
app.use(ElInput)
app.use(ElTable)
app.use(ElTableColumn)
app.use(ElConfigProvider, { locale: zhCn })
app.mount('#app')3.3 在组件内使用
<template>
<div>
<el-button type="primary" @click="handleClick">主要按钮</el-button>
<el-input v-model="value" placeholder="请输入" />
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
const value = ref('')
const handleClick = () => {
ElMessage.success('点击成功!')
}
</script>3.4 CSS 加载顺序说明
必须按以下顺序加载:
1. themes.css - 主题变量 (CSS Custom Properties)
2. styled.css - MacroUI 通用组件类
3. style.css - Vue 组件的微调和覆盖颠倒顺序可能导致主题变量被覆盖而出现视觉异常。
3.5 函数式调用(无需注册)
import { ElMessage, ElMessageBox, ElNotification, ElLoading } from '@macroui/macroui-vue'
ElMessage.success('成功')
ElNotification.error('失败')
const loader = ElLoading.service({ text: '加载中...' })4. 主题系统
4.1 切换主题
通过设置 <html data-theme="..."> 即可切换:
<html data-theme="light"> <!-- 默认 -->
<html data-theme="dark"> <!-- 暗色 -->
<html data-theme="cupcake"> <!-- 糖果粉 -->
<html data-theme="corporate"> <!-- 商务 -->
<html data-theme="dracula"> <!-- 德古拉 -->4.2 动态切换(带持久化)
// src/utils/theme.ts
import { ref, watchEffect } from 'vue'
const theme = ref(localStorage.getItem('theme') || 'light')
export function useTheme() {
watchEffect(() => {
document.documentElement.setAttribute('data-theme', theme.value)
localStorage.setItem('theme', theme.value)
})
const setTheme = (name: string) => {
theme.value = name
}
const toggleDark = () => {
setTheme(theme.value === 'dark' ? 'light' : 'dark')
}
return { theme, setTheme, toggleDark }
}<!-- 组件中 -->
<script setup lang="ts">
import { useTheme } from '@/utils/theme'
const { theme, setTheme } = useTheme()
</script>
<template>
<el-select v-model="theme" @change="setTheme">
<el-option label="浅色" value="light" />
<el-option label="暗色" value="dark" />
<el-option label="赛博朋克" value="cyberpunk" />
</el-select>
</template>4.3 内置主题清单(30+)
light、dark、cupcake、bumblebee、emerald、corporate、synthwave、retro、cyberpunk、valentine、halloween、garden、forest、aqua、lofi、pastel、fantasy、wireframe、black、luxury、dracula、cmyk、autumn、business、acid、lemonade、night、coffee、winter、dim、nord、abyss、silk、caramellatte、sunset。
4.4 自定义主题
/* src/styles/theme.css */
[data-theme="mytheme"] {
/* HSL 格式:H S% L% */
--p: 220 90% 56%; /* primary */
--pc: 0 0% 100%;
--s: 160 84% 39%;
--a: 30 90% 50%;
--n: 220 14% 28%;
--b1: 0 0% 100%;
--b2: 220 13% 95%;
--b3: 220 13% 90%;
--bc: 220 14% 10%;
--in: 198 93% 60%;
--su: 158 64% 52%;
--wa: 38 92% 50%;
--er: 0 91% 71%;
}<html data-theme="mytheme">5. 国际化 i18n
5.1 全局配置
import { ElConfigProvider } from '@macroui/macroui-vue'
import zhCn from '@macroui/macroui-vue/locale/lang/zh-cn'
import en from '@macroui/macroui-vue/locale/lang/en'
app.use(ElConfigProvider, {
locale: zhCn,
// size: 'default', // 全局组件尺寸
})5.2 运行时切换
<template>
<el-config-provider :locale="locale">
<app />
</el-config-provider>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import zhCn from '@macroui/macroui-vue/locale/lang/zh-cn'
import en from '@macroui/macroui-vue/locale/lang/en'
const locale = ref(zhCn)
function switchLang(lang: 'zh' | 'en') {
locale.value = lang === 'zh' ? zhCn : en
}
</script>5.3 useLocale Hook
<script setup lang="ts">
import { useLocale } from '@macroui/macroui-vue'
const { t } = useLocale()
console.log(t('el.pagination.total', { total: 100 })) // '共 100 条'
console.log(t('el.table.empty')) // '暂无数据'
</script>5.4 支持的语言(67 种)
| 区域 | 语言 | |------|------| | 中国大陆 | zh-cn | | 中国香港 | zh-hk | | 中国澳门 | zh-mo | | 中国台湾 | zh-tw | | 亚洲 | ja, ko, vi, th, my, hi, bn, ta, te, km, ur, pa, id, ms | | 欧洲 | en, de, fr, es, it, pt, pt-br, nl, ru, pl, tr, el, cs, da, sv, nb-no, fi, hu, ro, bg, uk, sk, hr, sl, sr, ca, eo, eu, et, lv, lt | | 中东 | ar, fa, he | | 非洲 | af, sw, mg | | 中亚 | kk, ky, tk, uz-uz | | 其他 | az, hy-am, ku, ckb, mn |
完整语言文件路径:
@macroui/macroui-vue/locale/lang/<code>
5.5 扩展新语言
// src/locales/ja.ts
export default {
name: 'ja',
el: {
button: {
confirm: '確認',
cancel: 'キャンセル',
},
pagination: {
total: '合計 {total} 件',
},
},
}// 注入到全局
import ja from '@/locales/ja'
app.use(ElConfigProvider, {
locale: ja,
})5.6 ⚠️ 重要规则
邮箱地址不要写入语言包,应写死在页面组件中。
✅ 正确:写死在组件中
<template>
<div>联系我们: [email protected]</div>
</template>
❌ 错误:写入语言包
export default {
contact: '[email protected]',
}6. 全局配置 ElConfigProvider
ElConfigProvider 用于全局配置组件默认值。
<template>
<el-config-provider
:locale="locale"
:size="size"
:button-type="buttonType"
:message-options="messageOptions"
:z-index="zIndex"
>
<app />
</el-config-provider>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import zhCn from '@macroui/macroui-vue/locale/lang/zh-cn'
import type { SizeType, ButtonType } from '@macroui/macroui-vue'
const locale = ref(zhCn)
const size = ref<SizeType>('default')
const buttonType = ref<ButtonType>('primary')
const zIndex = ref(2000)
</script>6.1 ElConfigProvider Props
| Prop | 类型 | 默认 | 说明 |
|------|------|------|------|
| locale | Language | zhCn | 当前语言 |
| size | SizeType | 'default' | 全局尺寸 |
| buttonType | ButtonType | - | 全局按钮类型 |
| messageOptions | MessageOptions | - | Message 全局配置 |
| zIndex | number | 2000 | 弹窗 z-index 起始值 |
| namespace | string | 'el' | 组件 CSS 类前缀 |
6.2 SizeType
'large' | 'default' | 'small' | 'xs' | 'sm' | 'md' | 'lg' | 'xl'
注:扩展尺寸(
xs/sm/md/lg/xl)仅 macroui-vue 支持,Element Plus 仅有前三档。
7. 组件完整参考
7.1 基础组件
ElButton — 按钮
<template>
<el-button>默认按钮</el-button>
<el-button type="primary">主要按钮</el-button>
<el-button type="success">成功按钮</el-button>
<el-button type="warning">警告按钮</el-button>
<el-button type="danger">危险按钮</el-button>
<el-button type="info">信息按钮</el-button>
<el-button plain>朴素按钮</el-button>
<el-button round>圆角</el-button>
<el-button circle>圆</el-button>
<el-button icon="Search">搜索</el-button>
<el-button loading>加载中</el-button>
<el-button size="large">大</el-button>
<el-button>默认</el-button>
<el-button size="small">小</el-button>
<el-button size="xs">超小</el-button>
<el-button-group>
<el-button icon="ArrowLeft">上一页</el-button>
<el-button icon="ArrowRight">下一页</el-button>
</el-button-group>
</template>Props 关键字段:type('primary' | 'success' | 'warning' | 'danger' | 'info' | 'default')、size、plain、round、circle、loading、disabled、icon、native-type、autofocus、tag、text / bg / link。
Events:click、mousedown。
Slots:default、loading、icon。
ElLink — 文字链接
<el-link href="https://element-plus.org" target="_blank">默认</el-link>
<el-link type="primary">主要</el-link>
<el-link :underline="false">无下划线</el-link>
<el-link disabled>禁用</el-link>ElText — 文本
<el-text>默认</el-text>
<el-text type="primary">主要</el-text>
<el-text type="danger">危险</el-text>
<el-text size="large">大号</el-text>
<el-text truncated>省略...</el-text>ElIcon — 图标
<el-icon><Edit /></el-icon>
<el-icon :size="20" color="#ff6b6b"><Search /></el-icon>ElSpace — 间距
<el-space>
<el-button>1</el-button>
<el-button>2</el-button>
</el-space>
<el-space direction="vertical" :size="20">
<el-card>1</el-card>
<el-card>2</el-card>
</el-space>
<el-space wrap :size="[10, 20]">
<el-button v-for="i in 10">按钮{{ i }}</el-button>
</el-space>ElDivider — 分割线
<el-divider />
<el-divider>文字</el-divider>
<el-divider direction="vertical">垂直</el-divider>
<el-divider border-style="dashed" />ElScrollbar — 滚动条
<el-scrollbar height="200px">
<p v-for="i in 50">{{ i }}</p>
</el-scrollbar>7.2 表单组件
ElInput — 输入框
<template>
<el-input v-model="value" placeholder="请输入" />
<el-input v-model="value" size="large" />
<el-input v-model="value" disabled />
<el-input v-model="value" clearable />
<el-input v-model="value" show-password />
<el-input v-model="value" :prefix-icon="Search" />
<el-input v-model="value" type="textarea" :rows="4" />
<el-input v-model="url">
<template #prepend>https://</template>
<template #append>.com</template>
</el-input>
<el-input v-model="value" maxlength="10" show-word-limit />
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { Search } from '@macroui/macroui-icons'
const value = ref('')
const textarea = ref('')
const url = ref('')
</script>Props:modelValue、type、placeholder、disabled、clearable、show-password、prefix-icon、suffix-icon、maxlength、minlength、show-word-limit、autocomplete、name、size、input-style。
Events:update:modelValue、input、change、focus、blur、clear、keydown、keyup。
Slots:prefix、suffix、prepend、append。
ElInputNumber — 数字输入
<el-input-number v-model="num" :min="1" :max="10" :step="1" />
<el-input-number v-model="num" controls-position="right" />
<el-input-number v-model="num" :precision="2" :step="0.1" />ElInputTag — 标签输入
<el-input-tag v-model="tags" placeholder="输入后回车" />ElInputOtp — 一次性密码
<el-input-otp v-model="otp" :length="6" />ElSelect — 选择器
<el-select v-model="value" placeholder="请选择" clearable filterable>
<el-option label="选项A" value="A" />
<el-option label="选项B" value="B" />
<el-option-group label="分组1">
<el-option label="选项C" value="C" />
</el-option-group>
</el-select>
<el-select v-model="values" multiple collapse-tags>
<el-option v-for="o in options" :key="o.value" :label="o.label" :value="o.value" />
</el-select>Props:modelValue、multiple、disabled、size、clearable、filterable、remote、loading-text、no-match-text、no-data-text、placeholder、collapse-tags、multiple-limit、value-key。
ElOption / ElOptionGroup
ElOption Props:value、label、disabled。
ElOptionGroup Props:label、disabled。
ElCascader — 级联选择
<el-cascader
v-model="value"
:options="options"
:props="{ value: 'id', label: 'name' }"
clearable
filterable
/>Props:modelValue、options、props、size、placeholder、disabled、clearable、filterable、show-all-levels、collapse-tags、separator、before-filter、max-collapse-tags。
ElTreeSelect — 树形选择
<el-tree-select v-model="value" :data="treeData" :props="defaultProps" />ElTree — 树形控件
<el-tree
:data="data"
:props="{ children: 'children', label: 'name' }"
show-checkbox
node-key="id"
default-expand-all
@check-change="handleCheck"
/>
<el-tree :load="loadNode" lazy :props="defaultProps" />ElTreeV2 — 虚拟树
<el-tree-v2 :data="data" :props="{ label: 'name' }" />ElCheckbox — 多选框
<el-checkbox v-model="checked">选项</el-checkbox>
<el-checkbox-group v-model="list">
<el-checkbox value="A">A</el-checkbox>
<el-checkbox value="B">B</el-checkbox>
</el-checkbox-group>
<el-checkbox :true-value="1" :false-value="0" v-model="value" />ElCheckboxGroup / ElCheckboxButton
<el-checkbox-group v-model="list">
<el-checkbox-button value="A">A</el-checkbox-button>
<el-checkbox-button value="B">B</el-checkbox-button>
</el-checkbox-group>ElRadio — 单选
<el-radio v-model="radio" :label="1">男</el-radio>
<el-radio-group v-model="radio">
<el-radio :label="1">男</el-radio>
<el-radio :label="2">女</el-radio>
</el-radio-group>
<el-radio-group v-model="radio">
<el-radio-button :label="1">男</el-radio-button>
<el-radio-button :label="2">女</el-radio-button>
</el-radio-group>ElSwitch — 开关
<el-switch v-model="value" />
<el-switch v-model="value" active-text="开" inactive-text="关" />
<el-switch v-model="value" inline-prompt active-text="Y" inactive-text="N" />
<el-switch v-model="value" loading />ElSlider — 滑块
<el-slider v-model="value" :min="0" :max="100" />
<el-slider v-model="range" range :min="0" :max="100" :step="10" />
<el-slider v-model="marks" :marks="{ 0: '0°C', 50: '50°C', 100: '100°C' }" />ElRate — 评分
<el-rate v-model="rate" />
<el-rate v-model="rate" show-score :max="10" />
<el-rate v-model="rate" allow-half />ElColorPicker — 颜色选择器
<el-color-picker v-model="color" show-alpha />
<el-color-picker v-model="color" color-format="hex" />
<el-color-picker v-model="color" :predefine="['#ff4500', '#ff8c00']" />ElDatePicker — 日期选择器
<el-date-picker v-model="date" type="date" placeholder="选择日期" />
<el-date-picker v-model="range" type="daterange" />
<el-date-picker v-model="month" type="month" />
<el-date-picker v-model="year" type="year" />
<el-date-picker v-model="datetime" type="datetime" />ElTimePicker — 时间选择器
<el-time-picker v-model="time" placeholder="选择时间" />
<el-time-picker v-model="range" is-range />
<el-time-picker v-model="time" format="HH:mm" arrow-control />ElTimeSelect — 时间段选择
<el-time-select
v-model="time"
start="08:30"
end="18:30"
step="00:15"
placeholder="选择时间"
/>ElUpload — 上传
<el-upload
action="/api/upload"
:headers="{ token: 'xxx' }"
:before-upload="beforeUpload"
:on-success="onSuccess"
:on-error="onError"
>
<el-button>点击上传</el-button>
</el-upload>
<el-upload drag>
<el-icon class="el-icon--upload"><upload-filled /></el-icon>
<div class="el-upload__text">
将文件拖到此处,或<em>点击上传</em>
</div>
</el-upload>ElForm — 表单
<template>
<el-form :model="form" :rules="rules" ref="formRef" label-width="100px">
<el-form-item label="用户名" prop="username">
<el-input v-model="form.username" />
</el-form-item>
<el-form-item label="邮箱" prop="email">
<el-input v-model="form.email" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submit">提交</el-button>
<el-button @click="reset">重置</el-button>
</el-form-item>
</el-form>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { FormInstance, FormRules } from '@macroui/macroui-vue'
const formRef = ref<FormInstance>()
const form = ref({ username: '', email: '' })
const rules: FormRules = {
username: [
{ required: true, message: '请输入用户名', trigger: 'blur' },
{ min: 3, max: 20, message: '长度在 3-20', trigger: 'blur' },
],
email: [
{ required: true, message: '请输入邮箱', trigger: 'blur' },
{ type: 'email', message: '邮箱格式不正确', trigger: 'blur' },
],
}
const submit = async () => {
if (!await formRef.value?.validate()) return
}
const reset = () => formRef.value?.resetFields()
</script>Form Methods(ref):validate(cb?)、validateField(props, cb?)、resetFields()、clearValidate(props?)、scrollToField(prop)。
ElFormItem Props:prop、label、label-width、required、rules、error、show-message、inline-message、size。
ElMention — @提及
<el-mention
v-model="value"
:options="[{ value: '张三', label: '张三' }]"
:prefix="['@', '#']"
/>ElAutocomplete — 自动补全
<el-autocomplete
v-model="value"
:fetch-suggestions="querySearch"
@select="handleSelect"
/>7.3 数据展示
ElTable — 表格
<el-table
:data="tableData"
stripe
border
height="400"
@selection-change="handleSelection"
>
<el-table-column type="selection" width="55" />
<el-table-column type="index" label="#" width="60" />
<el-table-column prop="name" label="姓名" sortable />
<el-table-column prop="age" label="年龄" sortable />
<el-table-column prop="address" label="地址" show-overflow-tooltip />
<el-table-column label="操作" width="120" fixed="right">
<template #default="{ row }">
<el-button size="small" @click="edit(row)">编辑</el-button>
</template>
</el-table-column>
</el-table>
<el-pagination
v-model:current-page="page"
v-model:page-size="size"
:total="total"
layout="total, sizes, prev, pager, next, jumper"
/>关键 Props:data、height、max-height、stripe、border、size、fit、show-header、highlight-current-row、row-class-name、row-style、cell-class-name、cell-style、empty-text、show-summary、summary-method、span-method、lazy、load、tree-props、default-expand-all、default-sort。
关键 Events:select、select-all、selection-change、cell-click、row-click、row-dblclick、sort-change、current-change、expand-change、filter-change。
ElTableColumn — 表格列
关键 Props:type(selection / index / expand)、prop、label、width、min-width、fixed、sortable、sort-orders、sort-method、sort-by、resizable、formatter、show-overflow-tooltip、align、header-align、class-name、label-class-name、selectable、reserve-selection、filters、filter-placement、filter-multiple、filter-method、filtered-value、render-header。
ElTableV2 — 虚拟表格
<el-table-v2 :columns="columns" :data="data" :width="800" :height="400" fixed />ElPagination — 分页
<el-pagination
v-model:current-page="currentPage"
v-model:page-size="pageSize"
:total="100"
:page-sizes="[10, 20, 50, 100]"
layout="total, sizes, prev, pager, next, jumper"
background
/>ElTag — 标签
<el-tag>标签1</el-tag>
<el-tag type="success">成功</el-tag>
<el-tag type="warning" closable>警告</el-tag>
<el-tag type="danger" effect="dark">危险</el-tag>
<el-tag size="large">大号</el-tag>
<el-tag round>圆角</el-tag>
<el-check-tag v-model="checked">可选中</el-check-tag>ElBadge — 徽章
<el-badge :value="12">
<el-button>按钮</el-button>
</el-badge>
<el-badge :value="3" :max="9">
<el-button>≤9</el-button>
</el-badge>
<el-badge is-dot>
<el-button>红点</el-button>
</el-badge>ElAvatar — 头像
<el-avatar :size="50" src="user.jpg" />
<el-avatar :size="50" icon="User" />
<el-avatar :size="50">USER</el-avatar>
<el-avatar-group>
<el-avatar src="1.jpg" />
<el-avatar src="2.jpg" />
</el-avatar-group>ElSkeleton — 骨架屏
<el-skeleton v-if="loading" :rows="5" animated />
<el-skeleton>
<template #template>
<el-skeleton-item variant="image" style="width: 200px; height: 100px;" />
<el-skeleton-item variant="h1" />
<el-skeleton-item variant="text" :rows="3" />
</template>
<template #default>真实内容</template>
</el-skeleton>ElProgress — 进度条
<el-progress :percentage="50" />
<el-progress :percentage="100" status="success" />
<el-progress :percentage="50" type="circle" :width="100" />
<el-progress :percentage="50" :duration="2" striped />ElEmpty — 空状态
<el-empty description="暂无数据" />
<el-empty :image-size="200">
<el-button type="primary">重新加载</el-button>
</el-empty>ElResult — 结果页
<el-result icon="success" title="成功" sub-title="操作已完成">
<template #extra>
<el-button type="primary">返回</el-button>
</template>
</el-result>ElDescriptions — 描述列表
<el-descriptions title="用户信息" :column="2" border>
<el-descriptions-item label="用户名">张三</el-descriptions-item>
<el-descriptions-item label="邮箱">[email protected]</el-descriptions-item>
<el-descriptions-item label="电话">13800138000</el-descriptions-item>
<el-descriptions-item label="地址" :span="2">北京市朝阳区</el-descriptions-item>
</el-descriptions>ElStatistic — 统计数值
<el-statistic title="活跃用户" :value="1024" />
<el-statistic :value="12345.67" :precision="2" title="销售额">
<template #suffix><span>元</span></template>
</el-statistic>
<el-countdown :value="Date.now() + 1000 * 60" title="倒计时" />ElTimeline — 时间轴
<el-timeline>
<el-timeline-item timestamp="2024-01-01" placement="top">
<el-card>创建项目</el-card>
</el-timeline-item>
<el-timeline-item timestamp="2024-02-01" type="primary" hollow>
<el-card>里程碑 1</el-card>
</el-timeline-item>
</el-timeline>ElCalendar — 日历
<el-calendar v-model="date">
<template #date-cell="{ data }">
<p :class="data.isSelected ? 'is-selected' : ''">
{{ data.day.split('-').slice(1).join('-') }}
</p>
</template>
</el-calendar>ElImage — 图片
<el-image
src="image.jpg"
:fit="'cover'"
:lazy="true"
:preview-src-list="[src1, src2]"
/>ElCarousel — 走马灯
<el-carousel :interval="3000" arrow="always" indicator-position="outside" height="200px">
<el-carousel-item v-for="item in 4" :key="item">
<h3>{{ item }}</h3>
</el-carousel-item>
</el-carousel>ElCollapse — 折叠面板
<el-collapse v-model="activeNames" accordion>
<el-collapse-item title="标题1" name="1">内容1</el-collapse-item>
<el-collapse-item title="标题2" name="2">内容2</el-collapse-item>
</el-collapse>ElTransfer — 穿梭框
<el-transfer
v-model="value"
:data="data"
filterable
:props="{ key: 'id', label: 'name' }"
/>ElWatermark — 水印
<el-watermark content="机密文件">
<div>有水印内容</div>
</el-watermark>7.4 反馈组件
ElAlert — 警告提示
<el-alert title="成功提示" type="success" />
<el-alert title="警告提示" type="warning" show-icon />
<el-alert title="错误提示" type="error" description="详细说明" closable />ElDialog — 对话框
<el-dialog v-model="visible" title="标题" width="500px" :before-close="handleClose">
<span>内容</span>
<template #footer>
<el-button @click="visible = false">取消</el-button>
<el-button type="primary" @click="confirm">确认</el-button>
</template>
</el-dialog>关键 Props:modelValue、title、width、fullscreen、top、modal、append-to-body、lock-scroll、close-on-click-modal、close-on-press-escape、show-close、before-close、draggable、overflow、center、align-center、destroy-on-close、transition。
ElDrawer — 抽屉
<el-drawer v-model="visible" title="抽屉" direction="rtl" size="400px">
<span>内容</span>
</el-drawer>关键 Props:modelValue、direction、size、title、modal、drawer-class、wrapper-closable、close-on-press-escape、destroy-on-close、with-header、show-close、z-index、append-to-body、lock-scroll。
ElMessage — 消息提示(函数式)
import { ElMessage } from '@macroui/macroui-vue'
ElMessage.success('操作成功')
ElMessage.warning('警告信息')
ElMessage.error('错误信息')
ElMessage.info('提示信息')
ElMessage({
message: '带图标',
type: 'success',
duration: 3000,
showClose: true,
dangerouslyUseHTMLString: true,
customClass: 'my-message',
onClose: () => console.log('closed'),
})MessageOptions:message、type、icon、dangerouslyUseHTMLString、customClass、duration、showClose、center、onClose、offset、appendTo、grouping。
ElMessageBox — 消息弹框
import { ElMessageBox } from '@macroui/macroui-vue'
await ElMessageBox.alert('内容', '标题', { type: 'warning' })
try {
await ElMessageBox.confirm('确定删除?', '提示', { type: 'warning' })
} catch {
// 取消
}
const { value } = await ElMessageBox.prompt('请输入名字', '提示', {
inputPattern: /^.{2,20}$/,
inputErrorMessage: '长度 2-20',
})ElNotification — 通知
import { ElNotification } from '@macroui/macroui-vue'
ElNotification({
title: '标题',
message: '内容',
type: 'success',
position: 'top-right',
duration: 4500,
})位置 options:top-right / top-left / bottom-right / bottom-left。
ElPopconfirm — 弹出确认
<el-popconfirm title="确定删除?" @confirm="handleConfirm" @cancel="handleCancel">
<template #reference>
<el-button>删除</el-button>
</template>
</el-popconfirm>ElTooltip — 文字提示
<el-tooltip content="提示内容" placement="top">
<el-button>悬停</el-button>
</el-tooltip>
<el-tooltip placement="bottom" effect="light">
<template #content>
<p>多行内容</p>
</template>
<el-button>亮色</el-button>
</el-tooltip>关键 Props:content、placement、disabled、offset、transition、show-after、hide-after、controlled、visible、trigger(hover / click / focus / contextmenu)、teleported。
ElPopover — 弹出框
<el-popover placement="top" :width="200" trigger="click">
<template #default>
<p>弹出内容</p>
</template>
<template #reference>
<el-button>点击触发</el-button>
</template>
</el-popover>ElLoading — 加载状态
<template v-loading="loading">内容</template>
<el-button @click="openFullScreen">全屏 loading</el-button>
<script setup lang="ts">
import { ElLoading } from '@macroui/macroui-vue'
const openFullScreen = () => {
const loading = ElLoading.service({
lock: true,
text: '加载中...',
background: 'rgba(0, 0, 0, 0.7)',
})
setTimeout(() => loading.close(), 3000)
}
</script>Options:target、fullscreen、lock、text、spinner、background、customClass。
ElTour — 漫游式引导
<el-tour v-model="open">
<el-tour-step target="#btn1" title="步骤1" description="说明1" />
<el-tour-step target="#btn2" title="步骤2" description="说明2" />
</el-tour>7.5 导航组件
ElMenu — 导航菜单
<el-menu :default-active="active" mode="horizontal">
<el-menu-item index="1">首页</el-menu-item>
<el-sub-menu index="2">
<template #title>产品</template>
<el-menu-item index="2-1">产品A</el-menu-item>
<el-menu-item index="2-2">产品B</el-menu-item>
</el-sub-menu>
<el-menu-item index="3">关于</el-menu-item>
</el-menu>
<el-menu default-active="1" :collapse="collapse">
...
</el-menu>关键 Props:mode(horizontal / vertical)、default-active、collapse、default-openeds、unique-opened、menu-trigger、router、collapse-transition、arrow-icon、ellipsis-icon。
ElMenuItem / ElSubMenu / ElMenuItemGroup
<el-menu-item index="1">
<template #title>
<el-icon><Edit /></el-icon>
<span>编辑</span>
</template>
</el-menu-item>
<el-sub-menu index="2">
<template #title>子菜单</template>
<el-menu-item-group title="分组">
<el-menu-item index="2-1">选项1</el-menu-item>
</el-menu-item-group>
</el-sub-menu>ElTabs — 标签页
<el-tabs v-model="activeName">
<el-tab-pane label="用户管理" name="first">内容1</el-tab-pane>
<el-tab-pane label="配置管理" name="second">内容2</el-tab-pane>
<el-tab-pane label="角色管理" name="third" lazy>内容3</el-tab-pane>
</el-tabs>
<el-tabs type="card">
...
</el-tabs>
<el-tabs type="border-card">
...
</el-tabs>关键 Props:v-model、type(card / border-card)、tab-position、closable、addable、editable、before-leave。
ElTabPane — 标签页内容
关键 Props:name、label、disabled、lazy、closable、contextmenu。
ElBreadcrumb — 面包屑
<el-breadcrumb separator="/">
<el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item>
<el-breadcrumb-item :to="{ path: '/list' }">列表</el-breadcrumb-item>
<el-breadcrumb-item>详情</el-breadcrumb-item>
</el-breadcrumb>ElDropdown — 下拉菜单
<el-dropdown trigger="click">
<span class="el-dropdown-link">下拉菜单<el-icon class="el-icon--right"><arrow-down /></el-icon></span>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item>选项1</el-dropdown-item>
<el-dropdown-item disabled>选项2(禁用)</el-dropdown-item>
<el-dropdown-item divided>选项3</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
<el-dropdown split-button @click="handleClick">
操作
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item>...</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>ElSteps — 步骤条
<el-steps :active="active" finish-status="success" align-center>
<el-step title="步骤1" description="说明1" />
<el-step title="步骤2" description="说明2" />
<el-step title="步骤3" description="说明3" />
</el-steps>
<el-steps :active="1" direction="vertical">
...
</el-steps>关键 Props:space、direction、active、align-center、simple、finish-status、process-status。
ElStep Props:title、description、icon、status。
ElPageHeader — 页头
<el-page-header title="返回" content="详情页" @back="goBack" />ElAffix — 固钉
<el-affix :offset="100">
<el-button>固定按钮</el-button>
</el-affix>ElBacktop — 回到顶部
<el-backtop :right="20" :bottom="20" />ElAnchor — 锚点
<el-anchor :offset="80">
<el-anchor-link href="#section-1" title="章节1" />
<el-anchor-link href="#section-2" title="章节2">
<el-anchor-link href="#section-2-1" title="章节2-1" />
</el-anchor-link>
</el-anchor>7.6 布局组件
ElContainer / ElHeader / ElAside / ElMain / ElFooter
<el-container>
<el-header>Header</el-header>
<el-container>
<el-aside width="200px">Aside</el-aside>
<el-main>Main</el-main>
</el-container>
<el-footer>Footer</el-footer>
</el-container>ElRow / ElCol — 栅格
<el-row :gutter="20">
<el-col :span="8">8/24</el-col>
<el-col :span="8">8/24</el-col>
<el-col :span="8">8/24</el-col>
</el-row>
<el-row :gutter="20" justify="center">
...
</el-row>
<el-row :gutter="20">
<el-col :xs="24" :sm="12" :md="8" :lg="6">响应式</el-col>
</el-row>
<el-row :gutter="20" type="flex" justify="start" align="middle">
<el-col :span="6">flex</el-col>
</el-row>ElRow:gutter、type、justify、align、tag。
ElCol:span、offset、push、pull、xs、sm、md、lg、xl、tag。
ElSplitter — 分隔面板
<el-splitter>
<el-splitter-panel :size="200">左</el-splitter-panel>
<el-splitter-panel>右</el-splitter-panel>
</el-splitter>ElSegmented — 分段控制器
<el-segmented v-model="value" :options="['日', '周', '月']" />
<el-segmented v-model="value" :options="options" size="large" block />ElBorder — 边框
<el-border>带边框容器</el-border>
<el-border :width="2" color="primary">自定义边框</el-border>ElInfiniteScroll — 无限滚动指令
<ul v-infinite-scroll="loadMore" :infinite-scroll-delay="200" :infinite-scroll-disabled="disabled">
<li v-for="item in items" :key="item.id">{{ item.name }}</li>
</ul>8. 工具函数与 Hooks
8.1 入口导出
import * as MacrouiVue from '@macroui/macroui-vue'
import {
ElMessage,
ElMessageBox,
ElNotification,
ElLoading,
} from '@macroui/macroui-vue'8.2 useLocale
import { useLocale } from '@macroui/macroui-vue'
const { t, locale } = useLocale()
t('el.pagination.total', { total: 100 })8.3 useZIndex
import { useZIndex } from '@macroui/macroui-vue'
const { initialZIndex, currentZIndex, nextZIndex } = useZIndex()
nextZIndex() // 取得下一个 z-index8.4 useNamespace
import { useNamespace } from '@macroui/macroui-vue'
const ns = useNamespace('button')
ns.b() // 'el-button'
ns.is('disabled') // 'is-disabled'
ns.m('primary') // 'el-button--primary'8.5 类型导出
import type {
ButtonType,
ButtonSize,
SizeType,
FormInstance,
FormRules,
FormItemRule,
MenuItemRegistered,
TableInstance,
TreeInstance,
UploadFile,
UploadFiles,
UploadUserFile,
TreeNodeData,
CascaderOption,
CascaderValue,
SelectOption,
SelectOptionGroup,
MessageOptions,
MessageType,
NotificationOptions,
DateCell,
CalendarInstance,
} from '@macroui/macroui-vue'8.6 工具函数
| 函数 | 用途 |
|------|------|
| useLocale() | 获取当前 locale |
| useZIndex() | z-index 管理 |
| useNamespace(name) | 类名前缀 |
| useId() | 生成唯一 id |
| useResizeObserver() | 监听 DOM 尺寸 |
| useEventListener() | 监听事件 |
| useThrottleFn() | 节流 |
| useDebounceFn() | 防抖 |
| useDraggable() | 拖拽(Dialog 等内部使用) |
9. 按需引入
9.1 自动按需(unplugin-vue-components)
npm install -D unplugin-vue-components// vite.config.ts
import Components from 'unplugin-vue-components/vite'
import { MacrouiVueResolver } from 'unplugin-vue-components/resolvers'
export default {
plugins: [
Components({
resolvers: [MacrouiVueResolver()],
}),
],
}9.2 手动按需(推荐用于 SSR)
import {
ElButton,
ElInput,
ElConfigProvider,
} from '@macroui/macroui-vue'9.3 在 Webpack 中按需
// babel.config.js
module.exports = {
plugins: [
['babel-plugin-import', {
libraryName: '@macroui/macroui-vue',
libraryDirectory: 'es',
style: true,
}, '@macroui/macroui-vue'],
],
}9.4 性能优化要点(v2.17.84+)
@macroui/macroui-vue 的 ESM 产物里,下述运行时依赖全部走 external,不会被打进 bundle:
| 依赖 | 角色 |
|------|------|
| vue | peer(必需) |
| @macroui/macroui-icons | 图标默认 external;通过 MacrouiIconsResolver 按需引入 |
| @vueuse/core | Tooltip / Dropdown 等使用的基础 hook |
| @popperjs/core | 旧版 Popper 定位(el-tooltip 等) |
| @floating-ui/dom | 新版 Floating 定位(el-floating) |
| lodash-unified | 通用工具函数 |
当前 ESM 体积拆解:
dist/index.mjs ~849 KB │ gzip: ~183 KB // 90+ 组件代码本体
dist/index.js ~613 KB │ gzip: ~151 KB // CJS 同步产物
dist/style.css ~291 KB │ gzip: ~41 KB // 全局样式
dist/locale/ ~216 KB │ gzip: ~6 KB // 67 种语言(仅打包用到的)按需引入结论:
- 全量注册:
app.use(MacrouiVue, ...),体积 ≈ 849 KB / 183 KB (gzip)。 - 按需 resolver(推荐):配合
MacrouiVueResolver+MacrouiIconsResolver,仅打包实际用到的组件,通常 < 200 KB (gzip)。 - 手动按需:参考 §9.2。
10. SSR / Nuxt
10.1 Nuxt 3 配置
// nuxt.config.ts
export default defineNuxtConfig({
build: {
transpile: ['@macroui/macroui-vue'],
},
vite: {
optimizeDeps: {
include: ['@macroui/macroui-vue'],
},
},
css: [
'@macroui/macroui/dist/themes.css',
'@macroui/macroui/dist/styled.css',
'@macroui/macroui-vue/dist/style.css',
],
})// plugins/macroui.ts
import MacrouiVue from '@macroui/macroui-vue'
export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.vueApp.use(MacrouiVue)
})10.2 SSR 注意事项
- 引用的组件必须出现在 template 中,否则会在 server 端跳过
- 使用
<client-only>包裹需要 client 行为的组件(如 ElTooltip、ElPopover) - 表单的
el-formSSR 推荐只渲染结构,校验放客户端
11. 浏览器支持
| 浏览器 | 版本 | |--------|------| | Chrome / Edge | 最近 2 年 | | Firefox | 最近 2 年 | | Safari | 14+ | | iOS Safari | 14+ | | Android Chrome | 90+ | | IE | ❌ 不支持 |
支持 Vue 3(>= 3.4)。
12. 开发与构建
12.1 仓库克隆
git clone https://github.com/mobiui/macroui.git
cd macroui-vue
pnpm install12.2 开发命令
# 库开发模式(监听源码,自动 build)
pnpm dev:lib
# 示例页面(examples/)
pnpm dev:demo
# 仅构建库
pnpm build:lib
# 完整构建(含 locale)
pnpm build:all
# 单元测试
pnpm test
pnpm test:watch
pnpm test:coverage
# E2E 测试
pnpm test:e2e
pnpm test:e2e:ui
# 代码风格
pnpm lint
# TypeScript 类型检查
pnpm typecheck12.3 目录结构
macroui-vue/
├── examples/ # 示例项目(vite demo)
│ ├── pages/
│ ├── App.vue
│ ├── main.ts
│ └── vite.config.ts
├── packages/
│ ├── components/ # 90+ 组件
│ │ ├── ElButton/
│ │ │ ├── button.vue
│ │ │ ├── props.ts
│ │ │ └── index.ts
│ │ └── ...
│ ├── constants/ # 常量
│ │ ├── aria.ts
│ │ ├── date.ts
│ │ ├── form.ts
│ │ ├── key.ts
│ │ └── size.ts
│ ├── hooks/ # Hooks
│ ├── locale/ # i18n 语言包
│ │ ├── index.ts
│ │ └── lang/
│ ├── styles/ # 组件局部样式
│ └── utils/ # 工具函数
├── tests/
│ ├── unit/ # 单元测试 (vitest)
│ └── e2e/ # E2E 测试 (playwright)
├── styles/
│ └── index.scss # 全局样式入口
├── docs/ # 文档
├── dist/ # 构建产物
└── types/ # 全局类型12.4 创建新组件
mkdir -p packages/components/ElNewComponent
touch packages/components/ElNewComponent/new-component.vue
touch packages/components/ElNewComponent/props.ts
touch packages/components/ElNewComponent/index.tsprops.ts:
import { buildProps } from '@macroui/macroui-vue'
import type { ExtractPropTypes, PropType } from 'vue'
export const newComponentProps = buildProps({
modelValue: {
type: [String, Number, Boolean],
default: '',
},
size: {
type: String,
values: ['large', 'default', 'small'],
default: 'default',
},
disabled: Boolean,
})
export const newComponentEmits = {
'update:modelValue': (value: any) => true,
}
export type NewComponentProps = ExtractPropTypes<typeof newComponentProps>
export type NewComponentEmits = typeof newComponentEmitsnew-component.vue:
<template>
<div class="el-new-component" :class="classes">
<slot />
</div>
</template>
<script setup lang="ts">
import { computed } from 'vue'
import { newComponentProps, newComponentEmits } from './props'
defineOptions({ name: 'ElNewComponent' })
const props = defineProps(newComponentProps)
const emit = defineEmits(newComponentEmits)
const classes = computed(() => [
`el-new-component--${props.size}`,
{ 'is-disabled': props.disabled },
])
</script>index.ts:
import { withInstall } from '@macroui/macroui-vue'
import NewComponent from './new-component.vue'
export const ElNewComponent = withInstall(NewComponent)
export default ElNewComponent12.5 添加到 packages/components/index.ts
export { ElNewComponent } from './ElNewComponent'13. NPM 发布
# 1. 确认登录状态
npm whoami
# 2. 修改 package.json 中的 version(遵循 semver)
# major:破坏性变更
# minor:向下兼容的新功能
# patch:bugfix
# 3. 构建
pnpm build:lib
# 4. 发布
npm publish --access public13.1 2FA Token 设置
如账户启用 2FA,需要 Granular Access Token:
- 访问 https://www.npmjs.com/settings/tokens
- 点击 Generate New Token → Granular Access Token
- 配置:
- Token Name:
macroui-vue-publish - Organization:
@macroui - Permissions: Publish packages ✅
- 2FA Bypass: ✅ 必须启用
- Token Name:
- 生成 Token
npm config set //registry.npmjs.org/:_authToken=YOUR_GRANULAR_TOKEN
npm publish --access public14. 项目结构
详见 12.3 目录结构。
15. 常见问题
Q1: 样式不生效?
- ✅ 检查 CSS 加载顺序:
themes.css→styled.css→style.css - ✅ 确认
<html data-theme="...">已设置 - ✅ 检查 Tailwind config 中是否覆盖了类名前缀
- ✅ 检查 scoped 样式是否影响组件
Q2: 组件不显示?
- ✅ 检查是否全局注册(
app.use(MacrouiVue)) - ✅ 检查是否局部注册 + 命名拼写
- ✅ 检查
<template>根节点是否就只有一个元素
Q3: TypeScript 类型错误?
- ✅ 运行
pnpm typecheck - ✅ 确保
@types/node已安装 - ✅ 检查
tsconfig.json中moduleResolution为bundler或node16
Q4: 主题切换无效?
- ✅ 注意
data-theme是属性,不是 CSS class - ✅ 自定义主题需匹配 HSL 格式(
H S% L%)
Q5: Dialog / Tooltip 不显示?
- ✅ 检查 z-index(默认 2000+),被遮挡时可显式设置
z-index - ✅ 检查
teleported是否为true
Q6: 国际化切换无效果?
- ✅ 使用
el-config-provider包裹根组件 - ✅ 邮箱地址不应写在语言包
Q7: 表单校验不生效?
- ✅
el-form-item必须设置prop - ✅
rules中使用{ required: true, message, trigger } - ✅ 校验触发使用
await formRef.value?.validate()是 Promise 式
16. 许可证
联系方式:[email protected]
🔗 相关项目
- @macroui/macroui — MacroUI 主题与样式
- @macroui/macroui-icons — 图标库
- Element Plus — API 兼容性参考
🔗 链接
- 仓库地址:https://github.com/mobiui/macroui
- 问题反馈:https://github.com/mobiui/macroui/issues
