引用参考:抖音"哲玄前端"《大前端全栈实践》
概述
基于领域模型概念设计了一套配置驱动的前端架构模式,通过JSON Schema(核心)配置文件驱动页面生成,实现了高度可配置化的管理系统。该架构采用模型-项目继承设计,支持多项目、多领域的复杂业务场景,有效解决了传统前端开发中的70-80%的重复性工作和维护难题。
一、核心设计理念
1.1 配置驱动开发
通过一套标准化的配置数据即可驱动生成整个站点的页面组件,将"手写代码"转变为"配置生成",大幅提升开发效率。
1.2 模型继承机制
基础模型配置可被多个项目继承和扩展(面向对象思维),支持内容沉淀的同时保持定制化灵活性,遵循DRY原则。
1.3 组件化架构
基于Vue 3的响应式组件化架构,支持动态组件渲染和组合,确保良好的可维护性和扩展性。
1.4 领域分离
按业务领域组织模型配置,不同领域可派生出对应的项目类型,保持业务逻辑的清晰分离。
二、解决的核心痛点
2.1 重复性CRUD开发
传统痛点:每个业务模块都需要重复编写表格、搜索、增删改查的代码解决方案:通过schema配置自动生成完整的CRUD界面
// 一个简单的schema配置即可生成完整的用户管理界面
schemaConfig: {
api: '/api/users',
schema: {
type: 'object',
properties: {
username: {
type: 'string',
label: '用户名',
tableOption: { width: 150 },
searchOption: { comType: 'input' }
}
}
}
}
2.2 组件复用困难
传统痛点:不同页面的表格、搜索组件功能差异大,难以复用解决方案:通过tableOption、searchOption等标准化配置实现组件的灵活定制
2.3 状态管理复杂
传统痛点:搜索条件、分页状态、选中状态需要手动管理解决方案:自动处理URL参数与搜索默认值的映射,实现状态持久化
三、架构设计
3.1 整体架构流程
graph TD
A[Model配置] --> B[Project继承]
B --> C[BFF层处理]
C --> D[Dashboard模板引擎]
D --> E[页面组件渲染]
E --> F[菜单系统]
E --> G[路由管理]
四、核心技术实现
4.1 配置继承机制
项目的核心创新在于实现了灵活的配置继承机制,通过model/index.js处理三种操作:
model/
├── business/ # 电商领域
│ ├── model.js # 基础模型配置
│ └── project/ # 具体项目配置
│ ├── pdd.js # 拼多多项目
│ ├── jd.js # 京东项目
│ └── taobao.js # 淘宝项目
├── course/ # 课程领域
│ ├── model.js # 基础模型配置
│ └── project/ # 具体项目配置
│ ├── bilibili.js # B站项目
│ └── douyin.js # 抖音项目
└── index.js # 模型加载器
实际案例:
// 配置继承处理逻辑
const projectExtendModel = (model, project) => {
return _.mergeWith({}, model, project, (modelValue, projValue) => {
if (Array.isArray(modelValue) && Array.isArray(projValue)) {
// 处理修改(重载): project有的键值,model也有
// 处理新增(拓展): project有的键值,model没有
// 处理保留(继承): model有的键值,project没有
return mergeArraysByKey(modelValue, projValue)
}
})
}
4.2 动态组件渲染
Schema配置解析
通过schema.js实现配置数据的智能解析和转换:
// 基础模型 (model/business/model.js)
{
menu: [{
key: 'product',
name: '商品管理',
schemaConfig: { /* 基础配置 */ }
}]
}
// 项目配置 (model/business/project/pdd.js)
{
name: '拼多多',
menu: [{
key: 'product',
name: '拼多多商品管理', // 修改:覆盖名称
}, {
key: 'client', // 新增:添加客户管理
name: '拼多多客户管理'
}]
}
SchemaOption的清洗和过滤
// 配置分离和转换
const buildDtoSchema = (_schema, comName) => {
const dtoSchema = { type: 'object', properties: {} }
for (const key in _schema.properties) {
const props = _schema.properties[key]
if (props[`${comName}Option`]) {
// 分离基础属性和组件配置
let dtoProps = { option: props[`${comName}Option`] }
dtoSchema.properties[key] = dtoProps
}
}
return dtoSchema
}
4.3 路由和视图管理
视图组件架构
- header-view: 头部菜单渲染,支持项目切换和多级菜单
- sider-view: 侧边栏复合视图,支持嵌套路由和默认选中
- schema-view: 配置驱动的CRUD页面核心组件
- iframe-view: 外部页面嵌入支持
4.4 Schema配置解析与数据流转
graph TD
A["原始Schema配置"] --> B["useSchema Hook"]
B --> C["buildDtoSchema处理"]
C --> D["tableSchema分离"]
C --> E["searchSchema分离"]
D --> F["Schema-Table组件"]
E --> G["Schema-Search-Bar组件"]
G --> H["动态组件渲染"]
H --> I["SearchItemConfig映射"]
I --> J["具体搜索组件<br/>(input/select/dynamicSelect)"]
F --> K["表格列动态生成"]
K --> L["数据格式化处理"]
L --> M["分页和操作按钮"]
动态组件注册机制
// search-item-config.js - 组件配置映射
const SearchItemConfig = {
input: { component: input },
select: { component: select },
dynamicSelect: { component: dynamicSelect },
dateRange: { component: dateRange }
}
// 动态组件渲染 - schema-search-bar.vue
<component
:is="SearchItemConfig[schemaItem.option?.comType]?.component"
:schema-key="key"
:schema="schemaItem"
@loaded="handleChildLoaded"
/>
4.5 数据请求与状态管理流程
sequenceDiagram
participant U as 用户操作
participant S as Schema-Search-Bar
participant SP as Search-Panel
participant SV as Schema-View
participant ST as Schema-Table
participant API as 后端API
U->>S: 输入搜索条件
S->>SP: emit('search', searchValObj)
SP->>SV: emit('search', searchValObj)
SV->>ST: 更新apiParams
ST->>API: GET /api/resource/list?params
API-->>ST: 返回分页数据
ST->>ST: buildTableData处理
ST-->>U: 渲染表格数据
4.6 配置继承详细机制
graph TD
A["基础model配置<br/>business/model.js"] --> B["项目配置<br/>business/project/pdd.js"]
B --> C["projectExtendModel函数"]
C --> D{"配置项Key匹配?"}
D -->|是| E["修改/重载<br/>使用project配置覆盖"]
D -->|否| F{"仅在project中存在?"}
F -->|是| G["新增/扩展<br/>添加新的配置项"]
F -->|否| H["保留/继承<br/>保持model原有配置"]
E --> I["合并后的最终配置"]
G --> I
H --> I
I --> J["传递给dashboard渲染"]
五、Schema配置标准
5.1 完整的配置案例对比
基础模型配置示例:
// model/business/model.js
module.exports = {
name: '电商系统',
menu: [{
key: 'product',
name: '商品管理',
moduleType: 'schema',
schemaConfig: {
api: '/api/proj/product',
schema: {
type: 'object',
properties: {
product_name: {
type: 'string',
label: '商品名称',
tableOption: { width: 200 },
searchOption: {
comType: 'dynamicSelect',
api: '/api/proj/product_enum/list'
}
},
price: {
type: 'number',
label: '价格',
tableOption: { width: 200 },
searchOption: {
comType: 'select',
enumList: [
{ label: '全部', value: -999 },
{ label: '¥39.9', value: 39.9 }
]
}
}
}
}
}
}]
}
项目继承配置示例:
// model/business/model.js
module.exports = {
name: '电商系统',
menu: [{
key: 'product',
name: '商品管理',
moduleType: 'schema',
schemaConfig: {
api: '/api/proj/product',
schema: {
type: 'object',
properties: {
product_name: {
type: 'string',
label: '商品名称',
tableOption: { width: 200 },
searchOption: {
comType: 'dynamicSelect',
api: '/api/proj/product_enum/list'
}
},
price: {
type: 'number',
label: '价格',
tableOption: { width: 200 },
searchOption: {
comType: 'select',
enumList: [
{ label: '全部', value: -999 },
{ label: '¥39.9', value: 39.9 }
]
}
}
}
}
}
}]
}
5.2 组件渲染架构图
graph TD
A["dashboard主容器"] --> B["Header-View<br/>头部菜单"]
A --> C["Main-Content<br/>主内容区域"]
B --> D["项目切换<br/>ProjectStore"]
B --> E["菜单渲染<br/>MenuStore"]
C --> F["Schema-View<br/>配置驱动页面"]
C --> G["Sider-View<br/>侧边栏复合视图"]
C --> H["Iframe-View<br/>外部页面嵌入"]
C --> I["Custom-View<br/>自定义页面"]
F --> J["Search-Panel<br/>搜索面板"]
F --> K["Table-Panel<br/>表格面板"]
J --> L["Schema-Search-Bar<br/>动态搜索栏"]
K --> M["Schema-Table<br/>动态表格"]
L --> N["Input组件"]
L --> O["Select组件"]
L --> P["DynamicSelect组件"]
L --> Q["DateRange组件"]
L --> Z["...其他扩展组件"]
M --> R["动态列渲染"]
M --> S["操作按钮"]
M --> T["分页组件"]
六、核心组件深度解析
6.1 Schema-Table组件技术实现
动态列渲染机制:
// schema-table.vue核心渲染逻辑
<template v-for="(schemaItem, key) in schema.properties">
<el-table-column
v-if="schemaItem.option.visible !== false"
:key="key"
:prop="key"
:label="schemaItem.label"
v-bind="schemaItem.option" // 动态绑定所有配置
/>
</template>
数据预处理机制:
const buildTableData = (listData) => {
return listData.map((rowData) => {
for (const dKey in rowData) {
const schemaItem = schema.value.properties[dKey]
// 处理数字精度格式化
if (schemaItem?.option?.toFixed) {
rowData[dKey] = rowData[dKey].toFixed(schemaItem.option.toFixed)
}
}
return rowData
})
}
6.2 Schema-Search-Bar组件生命周期
sequenceDiagram
participant SSB as Schema-Search-Bar
participant SC as 子搜索组件
participant SIC as SearchItemConfig
SSB->>SIC: 根据comType获取组件
SIC-->>SSB: 返回对应组件类
SSB->>SC: 动态创建组件实例
SC-->>SSB: emit('loaded')
SSB->>SSB: childComLoadedCount++
Note over SSB: 所有子组件加载完成后
SSB->>SSB: emit('load', getValue())
Note over SSB,SC: 用户操作阶段
SSB->>SC: 用户点击搜索
SC-->>SSB: getValue()获取当前值
SSB->>SSB: emit('search', searchObj)
6.3 URL状态管理与持久化
状态注入机制:
// schema.js中的URL参数处理
const dtoSearchSchema = buildDtoSchema(configSchema, 'search')
for (const key in dtoSearchSchema.properties) {
if (route.query[key] !== undefined) {
// 从URL参数注入默认值,实现状态持久化
dtoSearchSchema.properties[key].option.default = route.query[key]
}
}
路由状态同步流程:
graph LR
A["用户访问URL<br/>?proj_key=pdd&key=product&product_name=大前端实践课"] --> B["Route Query解析"]
B --> C["Schema Hook处理"]
C --> D["注入default值到Schema"]
D --> E["渲染搜索组件默认值"]
E --> F["自动执行搜索"]
F --> G["显示对应结果"]
H["用户修改搜索条件"] --> I["更新URL参数"]
I --> J["状态持久化"]
J --> K["刷新页面保持状态"]
七、架构优势与性能优化
7.1 组件缓存与性能优化
动态组件复用机制:
// SearchItemConfig组件单例模式
const SearchItemConfig = {
input: { component: input }, // 组件实例复用
select: { component: select },
// 避免重复创建组件实例,提升渲染性能
}
按需加载与路由分割:
// entry.dashboard.js中的路由懒加载
routes.push({
path: '/view/dashboard/schema',
component: () => import('./complex-view/schema-view/schema-view.vue')
})
7.3 扩展性设计模式
插件化组件注册:
// 支持新组件类型的动态扩展
const SearchItemConfig = {
// 原有组件
input: { component: input },
// 如果后续新增组件类型
richText: { component: richTextEditor },
imageUpload: { component: imageUploader },
// 无需修改核心代码,只需扩展配置
}
八、实践案例与效果展示
8.1 多项目配置继承实例
以拼多多项目为例,展示完整的配置继承效果:
graph TD
A["Business基础模型"] --> B["商品管理<br/>基础功能"]
A --> C["订单管理<br/>基础功能"]
A --> D["客户管理<br/>基础功能"]
E["拼多多项目配置"] --> F["商品管理(拼多多)<br/>继承+定制"]
E --> G["客户管理(拼多多)<br/>新增功能"]
E --> H["数据分析(拼多多)<br/>新增复合视图"]
E --> I["信息查询<br/>新增iframe集成"]
B --> F
D --> G
F --> J["最终页面:<br/>拼多多商品管理"]
G --> K["最终页面:<br/>拼多多客户CRM"]
H --> L["最终页面:<br/>数据分析仪表板"]
I --> M["最终页面:<br/>百度搜索集成"]
8.2 实际配置效果对比
一份配置,多端复用:
// 同一份商品配置,在不同项目中的表现
// 淘宝项目:展示"淘宝商品管理"
// 京东项目:展示"京东商品管理"
// 拼多多项目:展示"拼多多商品管理" + 额外的客户管理功能
总结
这套基于配置驱动的DSL架构通过以下核心实现:
- 配置即代码:将70-80%的重复性开发工作转化为配置编写
- 模型继承:基于面向对象思维的配置复用机制
- 组件化:高度解耦的动态组件渲染系统
- 标准化:基于JSON Schema的标准配置规范
需要注意的是,项目中许多关于设计的地方,可以多多反复观看,细细回味,如果当时有困惑,可以观看完整的视频后,回想设计的理念和思维,这个设计的思想值得用心去学习,如果当时不理解也没关系,总会有一刻融会贯通的感觉,流水不争先,争滔滔不绝,望大家一起加油。