前言
在现代前端开发中,如何通过一份配置驱动整个站点的生成,是提升开发效率的关键。本文将深入探讨如何利用领域模型DSL(Domain Specific Language)实现动态组件的渲染,完成从 模板→模型→项目→内容→应用 的完整链路。
回顾:领域模型架构建设
一、整体架构设计
1.1 核心理念
整个架构分为三层:
DSL 配置层 → Schema 解析层 → 视图渲染层
- DSL 配置层:定义模板、模型、项目、应用的配置
- Schema 解析层:解析配置生成 tableSchema、searchSchema、components
- 视图渲染层:根据解析结果渲染 Table、SearchBar、CreateForm、EditForm 等组件
1.2 设计目标
| 目标 | 说明 |
|---|---|
| 配置化 | 通过JSON配置描述页面结构和行为 |
| 组件化 | 动态渲染不同类型的组件 |
| 可扩展 | 支持自定义组件和配置扩展 |
| 低代码 | 减少重复代码,提升开发效率 |
二、Dashboard DSL 配置结构
2.1 顶层配置
{
model: "dashboard", // 模板类型
name: '电商系统', // 项目名称
menu: [...] // 菜单配置
}
2.2 菜单类型说明
菜单支持两种类型:
menuType: "group" - 菜单分组,包含 subMenu 子菜单(可递归)
menuType: "module" - 功能模块,支持以下 moduleType:
sider- 带侧边栏的布局,支持嵌套菜单iframe- 嵌入外部页面,通过 path 指定 URLcustom- 自定义路由,跳转到指定的 Vue 组件schema- ⭐ 核心能力:通过 Schema 配置动态渲染页面
三、Schema 配置详解
3.1 schemaConfig 整体结构
schemaConfig: {
api: '/api/proj/product', // RESTful API 地址
schema: {...}, // 数据模型定义
tableConfig: {...}, // 表格全局配置
componentConfig: {...} // 动态组件配置
}
3.2 Schema 数据模型示例
schema: {
type: 'object',
properties: {
product_id: {
type: 'string',
label: '商品ID',
tableOption: { width: 300, "show-overflow-tooltip": true },
editFormOption: { comType: 'input', disabled: true },
detailPanelOption: {}
},
product_name: {
type: 'string',
label: '商品名称',
maxLength: 10,
minLength: 3,
tableOption: { width: 200 },
searchOption: {
comType: 'dynamicSelect',
api: '/api/proj/product_enum/list'
},
createFormOption: { comType: 'input', default: '抖音哲玄' },
editFormOption: { comType: 'input', visible: false },
detailPanelOption: {}
},
price: {
type: 'number',
label: '价格',
maximum: 1000,
minimum: 30,
tableOption: { width: 200 },
searchOption: {
comType: 'select',
enumList: [
{ label: '全部', value: -1 },
{ label: '¥39.9', value: '39.9' },
{ label: '¥199', value: '199' },
{ label: '¥899', value: '899' }
]
},
createFormOption: { comType: 'inputNumber' },
editFormOption: { comType: 'inputNumber' },
detailPanelOption: {}
}
},
required: ['product_name']
}
3.3 字段配置映射关系
每个字段可以配置以下 Option,分别对应不同组件的渲染规则:
| Option | 对应组件 | 说明 |
|---|---|---|
| tableOption | Table Column | 表格列渲染配置 |
| searchOption | SearchBar | 搜索栏控件渲染配置 |
| createFormOption | CreateForm | 新建表单项配置 |
| editFormOption | EditForm | 编辑表单项配置 |
| detailPanelOption | DetailPanel | 详情面板展示配置 |
四、各 Option 配置详解
4.1 tableOption - 表格列配置
tableOption: {
width: 200, // 列宽
"show-overflow-tooltip": true, // 内容过长时显示 tooltip
}
4.2 searchOption - 搜索栏配置
普通下拉选择:
searchOption: {
comType: 'select',
enumList: [
{ label: '全部', value: -1 },
{ label: '¥39.9', value: '39.9' }
]
}
动态下拉选择:
searchOption: {
comType: 'dynamicSelect',
api: '/api/proj/product_enum/list'
}
输入框:
searchOption: {
comType: 'input'
}
日期范围:
searchOption: {
comType: 'dateRange'
}
4.3 createFormOption - 新建表单配置
// 输入框带默认值
createFormOption: {
comType: 'input',
default: '抖音哲玄'
}
// 数字输入框
createFormOption: {
comType: 'inputNumber'
}
// 下拉选择
createFormOption: {
comType: 'select',
enumList: [
{ label: '100', value: 100 },
{ label: '1000', value: 1000 },
{ label: '10000', value: 10000 }
]
}
4.4 editFormOption - 编辑表单配置
// 禁用编辑
editFormOption: {
comType: 'input',
disabled: true
}
// 不显示该字段
editFormOption: {
comType: 'input',
visible: false
}
// 数字输入框
editFormOption: {
comType: 'inputNumber'
}
4.5 detailPanelOption - 详情面板配置
detailPanelOption: {} // 空对象表示使用默认展示
五、tableConfig 与 componentConfig
5.1 tableConfig - 表格全局配置
tableConfig: {
// 表头按钮
headerButtons: [
{
label: '新增商品',
eventKey: 'showComponent',
eventOption: {
comName: 'createForm'
},
type: 'primary',
plain: true
}
],
// 行操作按钮
rowButtons: [
{
label: '查看详情',
eventKey: 'showComponent',
eventOption: {
comName: 'detailPanel'
},
type: 'primary'
},
{
label: '修改',
eventKey: 'showComponent',
eventOption: {
comName: 'editForm'
},
type: 'warning'
},
{
label: '删除',
eventKey: 'remove',
eventOption: {
params: {
product_id: 'schema::product_id'
}
},
type: 'danger'
}
]
}
5.2 componentConfig - 动态组件配置
componentConfig: {
createForm: {
title: '新增商品',
saveBtnText: '新增商品'
},
editForm: {
mainKey: 'product_id',
title: '修改商品',
saveBtnText: '修改商品'
},
detailPanel: {
mainKey: 'product_id',
title: '商品详情'
}
}
六、useSchema Hook 核心实现
6.1 Hook 职责
useSchema 是连接 DSL 配置与视图渲染的桥梁:
输入:
- route.query(路由参数)
- menuStore(菜单配置)
处理:
- 解析 schemaConfig
- 构建各组件专属 schema
- 过滤无关配置(降噪)
输出:
- api(数据接口)
- tableSchema + tableConfig
- searchSchema + searchConfig
- components(动态组件配置集合)
6.2 buildDtoSchema 降噪原理
原始 Schema 字段:
product_name: {
type: 'string',
label: '商品名称',
maxLength: 10,
minLength: 3,
tableOption: { width: 200 },
searchOption: { comType: '...' },
createFormOption: { ... },
editFormOption: { ... },
detailPanelOption: {}
}
经过 buildDtoSchema(schema, 'table') 处理后:
product_name: {
type: 'string',
label: '商品名称',
maxLength: 10,
minLength: 3,
option: { width: 200 } // 只保留 table 相关配置
}
七、数据流转示意
整体数据流转过程:
- DSL 配置 - JSON 配置文件定义页面结构
- menuStore - Pinia 状态管理存储菜单配置
- useSchema - Composable Hook 解析配置
- 分发到各组件 - tableSchema、searchSchema、components
- SchemaView - 统一视图容器渲染最终页面
八、设计优势与总结
8.1 设计优势
| 优势 | 说明 |
|---|---|
| 配置即代码 | 通过 JSON 配置描述页面,无需编写重复的 CRUD 代码 |
| 统一规范 | 所有页面遵循相同的配置规范,便于维护和理解 |
| 灵活扩展 | 支持自定义组件和配置项,满足个性化需求 |
| 降低耦合 | Schema 与视图组件解耦,修改配置即可更新页面 |
| 提升效率 | 新增页面只需添加配置,大幅减少开发时间 |
8.2 核心设计思想
- 单一数据源:一份 Schema 描述所有组件的渲染规则
- 配置驱动:通过 xxxOption 区分不同组件的配置
- 降噪处理:buildDtoSchema 过滤无关配置
- 响应式更新:watch 监听路由变化,自动重建配置
- 组件解耦:useSchema 作为中间层,连接配置与视图
结语
通过领域模型 DSL 的设计,我们实现了一份配置驱动整个页面的能力。useSchema Hook 作为核心桥梁,将复杂的 DSL 配置转换为各组件可消费的数据结构,大大提升了开发效率和代码可维护性。