概述
crud一直在做重复性工作,那么我们是不是可以将这些重复性工作去做一个配置化操作来减少这些无效的工作内容呢。依靠一份JSON Schema的数据去驱动架构配置,以配置化的方式去构建页面。
页面功能划分
- 横向导航区域(header-view)
- 纵向导航区域(sider-view)
- 内容展示区域(content-view)
内容展示区域有三种类型
- -嵌套内容 iframe-view,
- -自定义内容 custom-view,
- -模板内容 schema-view,
模板内容又可以细致划分成为
- -表单操作区schema-search-bar
- -表单内容区 shcema-table-view
js
|--------------------------------------------------------------|
#hearder-view
|-------------|------------------------------------------------|
| #sider-view | #content-view |
| | (schema-view) | (iframe-view) | (custom-view) |
| | (search-bar) | | |
| | --------------| | |
| | (table-view) | | |
|-------------|---------------|---------------|----------------|
那么基于此我们就可以开始进行构造一个我们基础的一个数据格式modal了
js
{
mode: 'dashboard',
name: '' // 名称,
desc: '' // 描述,
homePage: '' // 具体路径
menu: [
{
key: '',
name: '',
menuType: 'group/module', // group类型定义会存在自属的下拉菜单
// group类型下配置
submenu: [{}],
// module类型下配置
moduleType: 'iframe/custom/schema/sider', // 这里就对应我们上述设计的三大模块
`${moduleType}Config`: {
// sider类型
menu: [{}] //参考如上配置
// schema类型
api: '', //列表请求数据接口
schema: {
type: 'object',
properties: {
key: {
type: '', // 字段类型
label: '', // 字段名称
tableOptions: {
...elTableColunmConfig, // el-table-colunm 配置
visible: true // 是否显示字段
}
searchOptions: {
...elComponentConfig, // el-component 配置
comType: '' // 组件类型
defalut: '' // 默认展示值
// 当类型为select的时候
enmuList: [], // 配置下拉选项
}
}
}
}
tableConfig: {
headerButtons: [
{
label: '', // 按钮名称
eventKey: '', // 按钮事件标识
eventOption: {}, // 按钮具体配置
...elButtonConfig, // el-button配置
}
],
rowButtons: [
{
label: '', // 按钮名称
eventKey: '', // 按钮事件标识
eventOption: {
params: {
paramsKey: rowValueKey
}
}, // 按钮具体配置
...elButtonConfig, // el-button配置
}
]
} //配置table相关
searchConfig: {} // 配置搜索条件相关
// 其他类型
path: 'xxxxxx'
}
}
]
}
这样已经基础的modal模型就搭建好了,可以开始着手准备开发了
第一步我们将根据这个modal类型来创建一下我们的数据源,给定一个场景我们有多个系统,根据选择的不同系统展示不同的内容(但是结构是一致的)。

我们创建一个modal文件夹,每个modal文件夹的构造如下。 我们设计的思路如下,我们首先创建一个基类model.js,然后project.js中的是不同的子类,然后继承基类的相关内容,那么接下来就是实现这个继承功能
js
module.exports = (app) => {
// 遍历当前的model文件,确定好我们要操作的文件入口
// 遍历所有的js配置文件,通过文件名称来区分是子类还是基类
// 初始化构造数据结构,组合project和model,=> model.project, 将project挂载到model上
// 进一步整理数据,让project继承modal的内容(规则是先匹配key,遇到了就覆盖,如果内部还有相关数组就递归,没有就新增)
}
到这一步就已经处理好我们所需要的数据源格式了,接下来我们就要逐步实现我们的配置化渲染层面的代码了,规划一下我们的页面要展示成什么样子的。
首页
首页就需要展示各自modal和project大概内容 page下新建一个page-list的入口文件 我们需要实现一个组件header-container,主要分为三块区域左上方信息展示,右上方系统设置,以及中间的展示区域(使用插槽定义各个模块),然后在首页我们只需要自定义显示主题内容所以就使用template定位我们在header-container中的主要内容展示插槽,参考如下
js
|--------------------------------------------------------------|
#setting-content
|-------------|------------------------------------------------|
|#menu-content| #main-content |
| | |
|-------------|------------------------------------------------|
//page-list这个页面主要绘制main-content的显示和请求我们封装好的获取数据源接口model-list, 然后渲染出来
dashboard
page下新建一个dashboard文件,我们后续的dashBoard模块的内容都在下面实现
1.创建入口文件dashboard.vue
2.创建complex-view文件,新增header-view文件
js
// header-view 需要实现的就是动态渲染横向导航条数据,也就是menu下的各个对象渲染
// 这其中就包含了自带下拉内容的子项和需要渲染侧边栏的子项
// 其余的就渲染主体的main-content,main-content中又有多种类型区分,shcema-view就是我们这次主要实现的配置化页面
schema-view
重点实现这个配置化的页面
首先我们先将其拆分成两块内容
1.搜索区域
2.表单渲染区域
同理,那我们在schema-view下也创建一个complex-view文件用于存放我们的这两个组件 再来看下schema的配置
js
schemaConfig: {
api: "/api/proj/product",
schema: {
type: "object",
properties: {
product_id: {
type: "string",
label: "商品ID",
tableOption: {
width: 300,
"show-overflow-tooltip": true,
},
searchOption: {
comType: 'select',
enmuList: [{value:-1,label: '全部'}, {value: 1, label: 1}, {value: 2, label: 2}]
}
},
product_name: {
type: "string",
label: "商品名称",
tableOption: {
width: 200,
},
searchOption: {
comType: 'dynamicSelect'
}
},
price: {
type: "number",
label: "价格",
tableOption: {
width: 200,
},
searchOption: {
comType: 'input',
}
},
inventory: {
type: "number",
label: "库存",
tableOption: {
width: 200,
},
},
create_time: {
type: "string",
label: "创建时间",
tableOption: {},
searchOption: {
comType: 'dateRange'
},
},
},
tableConfig: {
headerButtons: [
{
label: "新增商品",
eventKey: "addProduct",
type: "primary",
plain: true,
},
],
rowButtons: [
{
label: "编辑",
eventKey: "editProduct",
type: "warning",
},
{
label: "删除",
eventKey: "deleteProduct",
eventOption: {
params: {
product_id: "schema::product_id",
},
},
type: "danger",
},
],
},
},
},
对于这一份的配置我们可以做到对一个字段进行列表和搜索的一起控制,这样我们就无需单独给搜索字段和列表字段都进行额外的处理了。这是一个思想,不单单是针对某一个功能,实际上后续我们如果想要扩展的话,可以依照此去进行配置。
回到schema-view的配置中,我们会实现一个hook,为什么需要实现这个hook呢,因为我们需要解析schema中配置,那么这份配置就在hook中实现,我们处理成我们需要的格式。
大体上简单描述了一下整体的实现过程,在这过程我们其实会对代码进行部分轻重构,将一些部分合理化简单化,例如watch监听多项,以及统一参数传递封装,路由hash等等,包括一些防抖节流类似的对接口请求的一些优化操作。我们在开发过程中发现问题,并且解决问题。而不是等到整体项目完结后才着手去做一个叫重构的事情,这样的话一旦代码间的联系多了起来,就会导致重构的难度变大。所有的组件实现都是通过入口-> 下发数据配置,行为管理 -> 具体功能实现,组件在开发过程中需要考虑三件事情,需要什么参数,接收什么数据,抛出哪些方法。
总结
总结一下,整体的思路,重点就是我们的所有开发都要依靠于这套配置文件,我们基于配置文件去进行模块的拆分,再进行功能的拆分,从而抽象各个模块的功能和各自负责的事项,赋予了可扩展性和易维护性。那么我们首先需要的就是了解我们在做什么,我们要做的东西是什么样的,大概的一个架构是怎么样的,我们才能够基于此去对其进行一个地基的建造,我们的大体方向才能够展示出来,再对其进行细致的拆分和梳理,完成各个分支的功能建设。
js
|--------------------------------------------------------------|
#hearder-view
|-------------|------------------------------------------------|
| #sider-view | #content-view |
| | (schema-view) | (iframe-view) | (custom-view) |
| | (search-bar) | | |
| | --------------| | |
| | (table-view) | | |
|-------------|---------------|---------------|----------------|
| |
BFF(通过bff层将配置数据返回给到页面)
----------------------------------------------------------------------
子类 子类 子类 子类 子类 子类 子类 子类 子类
| | |
基类 基类 基类
配置文件