外观
组件:按任务选择
@uadmin/ui 在 Element Plus 上提供页面组织、数据表和需要生命周期管理的组件。按钮、表单、输入框、标签仍直接使用 el-button、el-form、el-input、el-tag;不需要再包一层。
先选解决的问题
| 任务 | 选择 | 边界 |
|---|---|---|
| 统一页面标题、操作区和加载/失败状态 | UPage | 不创建路由,也不请求数据 |
| 显示当前菜单位置 | UBreadcrumb | 需要 Vue Router;UPage 已内置 |
| 搜索、分页、多选、列显隐 | UDataTable | 数据请求与服务端排序由页面负责 |
| 只有几列的静态表格 | UTable 或 el-table | UTable 只有列定义与单元格/操作插槽 |
| 按名字渲染图标 | UIcon / LucideIcon | 不依赖远程图标服务 |
| 图表随容器和主题变化 | UChart | 单独安装 ECharts,并从子路径导入 |
| 上传图片、附件、头像 | UUpload | 服务端存储、鉴权与 URL 生命周期由应用决定 |
| 编辑 HTML 正文 | URichText | 单独安装 wangEditor;不是 Markdown 编辑器 |
| 编辑并校验 JSON 文本 | UJsonEditor | 单独安装 CodeMirror 相关依赖;v-model 输出字符串 |
导入与环境
以下组件示例假设应用已安装 Vue 3、Element Plus 和 vue-i18n,并注册所用语言键。createUAdmin 消费方通常在 setup 中安装 Element Plus 与应用 i18n;已有应用可沿用自己的初始化。不要为单个页面重复创建应用或路由。
vue
<script setup lang="ts">
import { useI18n } from 'vue-i18n'
import { UPage, UCard } from '@uadmin/ui'
const { t } = useI18n({
useScope: 'local',
messages: {
'zh-CN': { title: '概览', description: '本月业务数据', section: '收入' },
'en-US': { title: 'Overview', description: 'Business this month', section: 'Revenue' },
},
})
</script>
<template>
<UPage :title="t('title')" :description="t('description')">
<UCard :title="t('section')">¥12,800</UCard>
</UPage>
</template>主入口会引入设计 token 与 Element Plus 主题桥接。基础组件采用主入口具名导入;三个重型组件用默认子路径导入:
ts
import UChart from '@uadmin/ui/components/UChart.vue'
import URichText from '@uadmin/ui/components/URichText.vue'
import UJsonEditor from '@uadmin/ui/components/UJsonEditor.vue'只安装实际使用的可选依赖,版本范围见各组件页。不要写 import { UChart } from '@uadmin/ui',主入口没有这个导出。
全局注册的实际范围
app.use(UAdminUIPlugin) 或 app.use(setupUAdminUI) 注册 UCard、UDialog、UIcon、USelect、UTable、UPage、UBreadcrumb、UUpload。不会注册 UDataTable、LucideIcon 或三个重型组件;这些仍需导入。局部导入更容易看清页面依赖。
小型语义组件
| 组件 | Props | Slots / Events | 使用要点 |
|---|---|---|---|
UCard | title?、description?、flush=false、shadow='never' | default、header、extra | flush 去掉内容内边距,适合表格;header 替换标题描述 |
UDialog | modelValue: boolean、title?、width=560 | default、footer;update:modelValue、confirm、cancel | confirm 不会自动关闭;异步保存成功后设置 model 为 false |
USelect | options: { label: string; value: string | number }[]、placeholder?、clearable=true | 其余属性/事件与插槽透传给 el-select | v-model 通过属性透传生效;默认宽度 180px,可用 style 覆盖 |
UTable | data、columns: UTableColumn[]、rowKey='id'、border=true | cell-字段名、actions,参数为表格行 scope | 列只支持 prop/label/width/minWidth;无内置分页、搜索或选择状态 |
vue
<script setup lang="ts">
import { ref } from 'vue'
import { useI18n } from 'vue-i18n'
import { UDialog } from '@uadmin/ui'
const { t } = useI18n()
const open = ref(false)
const saving = ref(false)
const props = defineProps<{ save: () => Promise<void> }>()
async function confirm() {
if (saving.value) return
saving.value = true
try {
await props.save()
open.value = false
} finally {
saving.value = false
}
}
</script>
<template>
<el-button @click="open = true">{{ t('common.edit') }}</el-button>
<UDialog v-model="open" :title="t('common.edit')">
<slot />
<template #footer>
<el-button @click="open = false">{{ t('common.cancel') }}</el-button>
<el-button type="primary" :loading="saving" @click="confirm">
{{ t('common.save') }}
</el-button>
</template>
</UDialog>
</template>该例由父页面传入真实 save 函数,并由该函数或统一 HTTP 层报告错误。关闭按钮和遮罩关闭不等同于默认取消按钮的 cancel 事件。
常见误区
UButton/UInput当前只是 Element Plus 兼容别名;新代码直接使用el-button/el-input。主入口没有UForm/UTag/UEmpty。- 通知、全屏和语言切换属于布局能力,不是此组件包的导出;不要从
@uadmin/ui导入NotificationBell等布局控件。 - 所有组件示例中的
t(...)键都应进入应用语言包;业务数据原文(用户名、正文等)不应当作语言键翻译。