Elpis 里程碑3 - 懒惰的码农

114 阅读3分钟

“里程碑,三段!”

看着师兄师妹们在合并请求列表文档上密密麻麻的学习进度,少年面无表情,唇角有着一抹自嘲,紧握的手掌,因为懒惰,而导致学习进度比刚进来的师弟师妹们都要缓慢,心里一阵阵钻心的疼痛…

回归正题!!!

什么是DSL

在这几个阶段的学习,一直听到学员们说 DSL DSL,现在终于知道是什么东东了。DSL(领域特定语言,Domain-Specific-Language),就是针对某一特定的领域或业务需求进行设计的计算机语言。

为什么要DSL

可以大大提高开发效率,减少增删改查调用和普通实现组件逻辑,通过简单的配置即可实现大部分业务

怎么用DSL

通过设计好的 schemaJson(“呐呐呐,不懂的同学自己去看文档了哈,这里就不过多展示了”)和对应的模块解析器绘制出对应的页面、组件、服务器、数据等

这里用 dashboard 模型为例

module.exports = {
  mode: 'dashboard', // 模板类型,不同模板类型对应不一样的模板数据结构
  name: '', // 名称
  desc: '', // 描述
  icon: '', // icon
  homePage: '', // 首页(项目配置)
  // 头部菜单
  menu: [{
    key: '', // 菜单唯一标识
    name: '', // 菜单名称
    menuType: '', // 枚举值: group / module
    
    // 当 menuType == group 时,可填
    subMenu: [{
      // 可递归 menuItem
    },],

    // 当 menuType == module 时,可填
    moduleType: '', // 枚举值: sider / iframe / custom / schema

    // 当 moduleType == sider 时,可填
    siderConfig: {
      menu: [{
        // 可递归 menuItem(除 moduleType == sider)
      },]
    },

    // 当 moduleType == iframe 时
    iframeConfig: {
      path: '', // iframe 路径
    },
    
    // 当 moduleType == custom 时
    customConfig: {
      path: '', // custom 路径
    },
    
    // 当 moduleType == schema 时
    schemaConfig: {
      api: '', // 数据源API(遵循 RESTFUL 规范)
      schema: { // 板块数据结构
        type: 'object',
        properties: {
          key: {
            ...schema, // 标准 schema 配置
            type: '', // 字段类型
            label: '', // 字段的中文名
            // 字段在 table 中的相关配置
            tableOption: {
              ...elTableColumnConfig, // 标准 el-table-column 配置
              toFixed: 0, // 保留小数点后几位
              visiable: true, // 默认为 true (false 时,表示不在表单中显示)
            },
            // 字段在 search-bar 中的相关配置
            searchOption: {
              ...eleComponentConfig, // 标准 el-component-column 配置
              comType: '', // 配置组件类型 input/select/...
              default: '', // 默认值

              // comType === 'select'
              enumList: [],

              // comType === 'dynamicSelect'
              api: ''
            },
            comOption: {},
            apiOption: {},
            dbOption: {}
          },
          // 其他字段
        }
      },
      // table 相关配置
      tableConfig: {
        headerButtons: [
          {
            label: '', // 按钮中文名
            eventKey: '', // 按钮事件名
            eventOption: {}, // 按钮具体配置
            ...elButtonConfig // 标准 el-button 配置
          }
        ],
        rowButtons: [
          {
            label: '', // 按钮中文名
            eventKey: '', // 按钮事件名
            eventOption: {
              // 当 eventKey === 'remove'
              params: {
                // paramsKey = 参数的键值
                // rowValueKey = 参数值 (当格式为 schema::tableKey 的时候,到 table 中找相应的字段)
                paramsKey: rowValueKey
              }
            }, // 按钮具体配置
            ...elButtonConfig // 标准 el-button 配置
          }
        ]
      },
      searchConfig: {}, // search-bar 相关配置
      comConfig: {}, // 模块组件
      apiConfig: {},
      dbConfig: {}
    }
  }]
}

核心实现:menu、schema

1、通过菜单(menu),确定页面要渲染的模块如侧边栏(sider)、嵌套页面(iframe)、自定义页面(custom)、通用页面(schema)

2、通过 schema + config 实现业务,如通过searchBar解析器(searchSchema + searchConfig)实现出搜索栏功能,通过表格解析器(tableSchema + tableConfig)渲染对应的表格内容

配置项过多怎么办?

这里在 dashboard 中配置了一个 hook 文件,用来过滤掉无关配置项,部分核心代码如下

// hook.js
nextTick(() => {
  // 构造 tableSchema 和 tableConfig
  tableSchema.value = buildDtoSchema(configSchema, 'table');
  tableConfig.value = sConfig.tableConfig;
  // 构造 searchSchema 和 searchConfig
  const dtoSearchSchema = buildDtoSchema(configSchema, 'search');
  // 如果网页或路由跳转进入页面时带有条件,需要把条件加上
  for (const key in dtoSearchSchema.properties) {
    if (route.query[key] !== undefined) {
      dtoSearchSchema.properties[key].option.default = route.query[key];
    }
  }
  searchSchema.value = dtoSearchSchema;
  searchConfig.value = sConfig.searchConfig;
});

当需要渲染搜索栏和表格时,通过hook把对应的配置项分离出来,过滤掉其他无关配置项,使用时达到页面数据结构单一的效果。

用在什么地方

  • 当需要快速搭建一个售前项目用来展示演示时
  • 当项目出现多个相同页面、通用页面时,如数据管理系统,后台管理系统等,可以减少重复性代码
  • 类似数据的增删改查,如表格、表单、菜单、搜索栏、模块复用、API复用

总结

通过DSL实现设计,减少了接近80%的页面设计,还提供了多个插槽可供页面自定义业务逻辑实现,即20%的客制化友好开发。