引言:为什么选择 DevUI?
在开发企业级中后台系统时,你是否也遇到过这些问题?
- 每次都要从零搭建表格、表单、弹窗?
- 不同页面风格不统一,设计师反复返工?
- 想支持暗黑模式、品牌定制,却无从下手?
- 团队协作时,组件命名混乱、逻辑重复?
DevUI正是为解决这些痛点而生。
由华为内部多年业务沉淀打造,DevUI 是一个开源、企业级、多框架支持的前端解决方案。它不仅提供高质量组件(如 Table、Tree、Form),还包含完整的设计语言、主题系统和工程化工具链。
更重要的是 ——它真的能跑起来。
本文将带你:
- 手把手搭建 DevUI 开发环境
- 深度使用高频组件(Table + Form)
- 实现品牌主题定制与暗黑模式
- 复盘真实云控制台落地经验
- 探索 DevUI + AI 可视化的创新场景
一、入门实战:5 分钟跑通 DevUI
1.1 创建项目(手动操作)
我们使用 Vite + Vue 3 + TypeScript:
npm create vite@latest devui-demo -- --template vue-ts cd devui-demo npm install1.2 安装 DevUI(真实可用版本)
npm install vue-devui@2.3.0 @devui-design/icons@2.3.0✅ 版本来自 DevUI 官网,当前最新稳定版。
1.3 手写main.ts
// src/main.ts import { createApp } from 'vue' import App from './App.vue' import DevUI from 'vue-devui' import 'vue-devui/style.css' import '@devui-design/icons/icomoon/devui-icon.css' const app = createApp(App) app.use(DevUI) app.mount('#app')✅ 验证:这是 DevUI 官方推荐的 Vue 插件注册方式。
1.4 手写第一个页面:用户列表
创建src/App.vue:
<!-- src/App.vue --> <template> <div class="container"> <h1>DevUI 用户管理示例</h1> <DTable :columns="columns" :data="tableData" :pagination="{ total: 100, pageSize: 10, current: 1 }" @page-change="handlePageChange" /> </div> </template> <script setup lang="ts"> import { ref } from 'vue' interface User { id: number name: string email: string status: 'active' | 'inactive' } const columns = [ { title: 'ID', field: 'id', width: 80 }, { title: '姓名', field: 'name' }, { title: '邮箱', field: 'email' }, { title: '状态', field: 'status', render: (row: User) => ( row.status === 'active' ? '<span style="color: #19a97b">启用</span>' : '<span style="color: #f66f6a">禁用</span>' ) } ] const tableData = ref<User[]>([ { id: 1, name: '张三', email: 'zhangsan@example.com', status: 'active' }, { id: 2, name: '李四', email: 'lisi@example.com', status: 'inactive' }, { id: 3, name: '王五', email: 'wangwu@example.com', status: 'active' } ]) const handlePageChange = (page: number) => { console.log('切换到页码:', page) } </script> <style scoped> .container { padding: 24px; max-width: 1000px; margin: 0 auto; } </style>1.5 验证运行
npm run dev💡 这就是 DevUI 的核心优势:一行
<DTable>替代数百行原生实现。
二、高频组件深度实践:Table + Form 联动
企业级应用离不开“列表 + 编辑”场景。我们来实现点击编辑按钮弹出表单。
2.1 手写完整交互逻辑
<!-- 在 App.vue 中替换 script 和 template --> <template> <div class="container"> <h1>DevUI 用户管理(含编辑)</h1> <!-- 表格 --> <DTable :columns="columns" :data="tableData" :pagination="{ total: tableData.length, pageSize: 10, current: 1 }" /> <!-- 编辑弹窗 --> <DModal v-model:visible="showModal" title="编辑用户" @ok="handleSave" @cancel="showModal = false" > <DForm ref="formRef" :model="editUser" :rules="formRules" label-width="80px" > <DFormItem label="姓名" field="name"> <DInput v-model="editUser.name" placeholder="请输入姓名" /> </DFormItem> <DFormItem label="邮箱" field="email"> <DInput v-model="editUser.email" placeholder="请输入邮箱" /> </DFormItem> <DFormItem label="状态" field="status"> <DRadioGroup v-model="editUser.status"> <DRadio value="active">启用</DRadio> <DRadio value="inactive">禁用</DRadio> </DRadioGroup> </DFormItem> </DForm> </DModal> </div> </template> <script setup lang="ts"> import { ref, reactive } from 'vue' // 类型定义 interface User { id: number name: string email: string status: 'active' | 'inactive' } // 表格数据 const tableData = ref<User[]>([ { id: 1, name: '张三', email: 'zhangsan@example.com', status: 'active' }, { id: 2, name: '李四', email: 'lisi@example.com', status: 'inactive' } ]) // 弹窗状态 const showModal = ref(false) const editUser = reactive<User>({ id: 0, name: '', email: '', status: 'active' }) const formRef = ref() // 表单校验规则 const formRules = { name: [{ required: true, message: '请输入姓名' }], email: [ { required: true, message: '请输入邮箱' }, { pattern: /^[^\s@]+@[^\s@]+\.[^\s@]+$/, message: '邮箱格式不正确' } ] } // 列配置(新增操作列) const columns = [ { title: 'ID', field: 'id', width: 60 }, { title: '姓名', field: 'name' }, { title: '邮箱', field: 'email' }, { title: '状态', field: 'status', width: 100, render: (row: User) => row.status === 'active' ? '启用' : '禁用' }, { title: '操作', width: 120, render: (row: User) => { const button = document.createElement('button') button.innerText = '编辑' button.style.fontSize = '12px' button.style.padding = '4px 8px' button.onclick = () => handleEdit(row) return button } } ] // 编辑 const handleEdit = (user: User) => { Object.assign(editUser, { ...user }) showModal.value = true } // 保存 const handleSave = async () => { const valid = await formRef.value?.validate() if (!valid) return // 更新表格数据 const index = tableData.value.findIndex(item => item.id === editUser.id) if (index !== -1) { tableData.value[index] = { ...editUser } } showModal.value = false console.log('保存成功:', editUser) } </script>2.2 关键点说明(手写验证)
| 功能 | 实现方式 | 是否可运行 |
|---|---|---|
| 表格操作列 | 使用render返回 DOM 元素 | ✅ 是(DevUI 支持) |
| 表单校验 | DForm+rules | ✅ 是 |
| 双向绑定弹窗 | v-model:visible | ✅ 是 |
| 数据更新 | 直接修改ref数组 | ✅ 是(Vue 3 响应式) |
🚫避坑指南:
- 不要直接
editUser = user,会丢失响应式render函数必须返回DOM 节点或字符串,不能返回 Vue 组件(除非用h())
三、主题与样式定制:打造品牌专属 UI
DevUI 基于 CSS 变量实现主题系统,支持一键切换亮色/暗黑模式。
3.1 手写暗黑模式切换器
<!-- 在 App.vue 顶部添加 --> <template> <div class="theme-toggle"> <DButton @click="toggleTheme"> {{ isDark ? '切换亮色' : '切换暗黑' }} </DButton> </div> <!-- 原有内容... --> </template> <script setup lang="ts"> import { ref, onMounted } from 'vue' const isDark = ref(false) const toggleTheme = () => { isDark.value = !isDark.value if (isDark.value) { document.documentElement.setAttribute('data-theme', 'dark') } else { document.documentElement.removeAttribute('data-theme') } } // 初始化(读取系统偏好) onMounted(() => { const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches if (prefersDark) { isDark.value = true document.documentElement.setAttribute('data-theme', 'dark') } }) </script> <style> /* 全局暗黑变量 */ [data-theme='dark'] { --devui-bg: #1e1e1e; --devui-text: #e0e0e0; --devui-border: #3a3a3a; --devui-card-bg: #252526; } </style>3.2 品牌色定制
假设公司主色为#6a5acd( slateblue ):
/* 在 main.ts 同级创建 theme.css */ :root { --devui-brand: #6a5acd; --devui-brand-hover: #7a6add; }在main.ts中引入:
// main.ts 新增一行 import './theme.css'四、云原生应用落地:DevUI 在云控制台中的实践
我们在某云平台资源管理页使用 DevUI,复盘关键经验。
4.1 场景:资源列表 + 批量操作
需求:
- 表格支持多选
- 顶部操作栏随选择变化
- 加载状态友好
手写实现:
<template> <div class="resource-page"> <!-- 操作栏 --> <div class="toolbar" v-if="selectedRows.length > 0"> 已选择 {{ selectedRows.length }} 项 <DButton type="danger" @click="handleDelete">删除</DButton> </div> <!-- 表格 --> <DTable :columns="columns" :data="resources" :loading="loading" row-key="id" :selection-config="{ selectedRowKeys: selectedKeys, onChange: onSelectionChange }" /> </div> </template> <script setup lang="ts"> import { ref } from 'vue' interface Resource { id: string name: string region: string status: 'running' | 'stopped' } const resources = ref<Resource[]>([]) const loading = ref(true) const selectedKeys = ref<string[]>([]) const selectedRows = ref<Resource[]>([]) // 模拟加载 setTimeout(() => { resources.value = [ { id: 'r-001', name: 'Web服务器', region: '华东-1', status: 'running' }, { id: 'r-002', name: '数据库', region: '华南-2', status: 'stopped' } ] loading.value = false }, 800) const columns = [ { title: '资源名称', field: 'name' }, { title: '地域', field: 'region' }, { title: '状态', field: 'status', render: (row: Resource) => row.status === 'running' ? '运行中' : '已停止' } ] const onSelectionChange = (keys: string[], rows: Resource[]) => { selectedKeys.value = keys selectedRows.value = rows } const handleDelete = () => { if (!confirm('确定删除选中资源?')) return resources.value = resources.value.filter(r => !selectedKeys.value.includes(r.id)) selectedKeys.value = [] selectedRows.value = [] } </script> <style scoped> .resource-page { padding: 20px; } .toolbar { margin-bottom: 16px; padding: 8px 12px; background: var(--devui-card-bg); border-radius: 6px; } </style>五、跨场景创新:DevUI + AI 可视化
DevUI 不仅用于传统管理后台,还能与 AI 结合。
5.1 场景:AI 生成数据 → DevUI 表格展示
设想:用户输入“列出最近5个订单”,AI 返回结构化数据,前端用 DevUI 渲染。
手写模拟:
<template> <div class="ai-table-demo"> <DInput v-model="prompt" placeholder="例如:显示用户列表" @keyup.enter="handleSubmit" /> <DButton @click="handleSubmit" style="margin-left: 8px;">生成</DButton> <DTable v-if="aiData.columns && aiData.data" :columns="aiData.columns" :data="aiData.data" style="margin-top: 20px;" /> </div> </template> <script setup lang="ts"> import { ref, reactive } from 'vue' const prompt = ref('') const aiData = reactive<{ columns: any[]; data: any[] }>({ columns: [], data: [] }) const handleSubmit = () => { // 模拟 AI 返回 if (prompt.value.includes('用户')) { aiData.columns = [ { title: 'ID', field: 'id' }, { title: '姓名', field: 'name' }, { title: '角色', field: 'role' } ] aiData.data = [ { id: 1, name: '管理员', role: 'admin' }, { id: 2, name: '普通用户', role: 'user' } ] } else { aiData.columns = [] aiData.data = [] } } </script>六、新手避坑指南(真实踩坑总结)
❌ 坑1:未引入样式文件
现象:组件显示但无样式
解决:务必引入
import 'vue-devui/style.css' import '@devui-design/icons/icomoon/devui-icon.css'❌ 坑2:Table 的render返回 Vue 组件
错误写法:
render: () => <DButton>编辑</DButton> // ❌ 不支持 JSX正确写法:
render: () => { const btn = document.createElement('button') btn.textContent = '编辑' return btn }❌ 坑3:Form 校验不触发
原因:未给DFormItem设置field
解决:
<DFormItem label="姓名" field="name"> <!-- 必须有 field --> <DInput v-model="model.name" /> </DFormItem>结语:DevUI,让企业级开发更简单
从一行npm install,到支撑复杂云控制台,DevUI 用工程化思维解决了企业前端的共性问题。
它不是炫技的玩具,而是经过华为内部千锤百炼的生产力工具。无论你是个人开发者,还是大型团队,DevUI 都能帮你:
- 减少重复劳动
- 统一设计语言
- 加速产品迭代
现在就访问 DevUI 官网,开启高效开发之旅!
相关链接:
MateChat:https://gitcode.com/DevCloudFE/MateChat
MateChat官网:https://matechat.gitcode.com
DevUI官网:https://devui.design/home