学习 elpis 有感 -- 初识 DSL (低代码模式开发环境)

864 阅读5分钟

什么是DSL?

你是一名前端开发,你是否有过如此共鸣?每天80%的工作量都是重复性的增删改查,只有20%的工作处于可拓展空间。感觉每天都很忙,但却学不到什么东西?如果有一种模式能取代这种笨拙的工作模式,把大量的时间用在做高效的事情上,反之要尽可能地缩短这段重复性高的堆代码环节,那么无论对于程序员自身能力还是企业的用人成本,都会带来极大高效的提升。

于是 DSL 诞生了。

DSL简介

DSL(领域特定语言,Domain-Specific-Language)是一种计算机编程语言,专门为解决某一类问题而设计。与通用编程语言相比,DSL具有更贴近问题领域的语法和语义,能够更加简洁、直接地表达解决方案。以下是DSL设计的一些好处:

  1. 提高表达力:DSL 通过提供一套贴近问题域的概念和术语,使得开发者能够用更接近自然语言或业务语言的方式来描述解决方案,从而提高了代码的可读性和可维护性。
  2. 增强抽象层次:DSL 允许对问题域进行更高层次的抽象,减少了实现细节的干扰,使开发人员可以专注于解决实际问题而不是底层技术细节。
  3. 简化复杂性:对于复杂的业务逻辑或者配置,使用 DSL 可以大大简化表述方式,降低出错几率,并且更容易被非技术人员理解。
  4. 促进协作:由于 DSL 更加贴近业务需求,它可以帮助不同背景的利益相关者之间建立更好的沟通桥梁,例如程序员与业务分析师之间的交流
  5. 提升生产力:一旦掌握了特定领域的 DSL,开发人员可以在该领域内快速编码,因为DSL减少了通用编程语言中不必要的语法负担,让开发者能更高效地编写代码。
  6. 易于测试:良好的 DSL 设计可以使编写的程序结构更加清晰,这有助于创建自动化测试脚本,确保系统的稳定性和可靠性。
  7. 定制化:DSL 可以为不同的项目量身定制,满足特定行业或应用的独特需求,提供更高的灵活性。
  8. 学习曲线较低:对于已经熟悉该领域的人来说,DSL 的学习成本通常比学习一门全新的通用编程语言要低得多。

实现DSL

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 == side)
                    },
                ],
            },
            // 当 moduleType == iframe 时
            iframeConfig: {
                path: "", // iframe 路径
            },
            // 当 moduleType == custom 时
            customConfig: {
                path: "", // 自定义路由路径
            },
            // 当 moduleType == schema 时
            schemaConfig: {
                api: "/api/user", // 数据源 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: {
                                ...elComponentConfig, // 标准 el-component-column 配置
                                comType: "", // 配置组件类型 input/select/...
                                default: "", // 默认值
                                // comType === 'select'
                                enumList: [], // 下拉框可选项
                                // comType === 'dynamicSelect'
                                api: "",
                            },
                        },
                    },
                },
            },
            // table 相关配置
            tableConfig: {
                headerButtons: [
                    {
                        label: "", // 按钮中文名
                        eventKey: "", // 按钮事件名
                        eventOption: {}, // 按钮事件具体配置
                        ...elButtonConfig, // 标准 el-button 配置
                    },
                ],
                rowButtons: [
                    {
                        label: "", // 按钮中文名
                        eventKey: "", // 按钮事件名
                        eventOption: {
                            // 当 eventKey == "remove"
                            params: {
                                // paramKey = 参数的键值
                                // paramValue = 参数值,格式为 schema::tableKey,到 table 中找相应的字段
                                paramKey: rowValueKey,
                            },
                        }, 
                        // 按钮事件具体配置
                        ...elButtonConfig, // 标准 el-button 配置
                    },
                ],
            },
            searchConfig: {}, // search-bar 相关配置
            components: {}, // 模块组件
        },
    ],
};

以上是我的 dsl 配置,不喜勿喷,欢迎交流。

这份配置通过 moduleType,将页面分为了四种类型:

  1. sider -- 含有侧边栏的页面
  2. iframe -- 嵌套 iframe 页面
  3. custom -- 自定义路由路径
  4. schema -- schema 配置 也就是本文的核心配置

schemaConfig 详解

api 即是当前模块的数据源 API,例如我现在要配置一个用户管理页面,那么我的 api 可以配置成 '/api/user',在 RESTFUL 规范下,增删改查的接口名都可以通过这个 api 配置生成。

schema 中的 properties 里边装的是不同的 key。这些 key 又是 schema 的核心。可以通过配置 tableOption、searchOption 来实现在 el-table、search-bar 组件中的展示状态,同样这套 key 也可以间接生成一份数据库表。下面我将通过一份实战案例具体详解。

schemaConfig: {
    api: "/api/proj/product",
    schema: {
        type: "object",
        properties: {
            product_id: {
                type: "string",
                label: "商品ID",
                tableOption: {
                    width: 300,
                    "show-overflow-tooltip": true,
                },
            },
            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: -1 },
                        { label: "¥39.9", value: 39.9 },
                        { label: "¥199", value: 199 },
                        { label: "¥899", value: 899 },
                    ],
                },
            },
            inventory: {
                type: "number",
                label: "库存",
                tableOption: {
                    width: 200,
                },
                searchOption: {
                    comType: "input",
                },
            },
            create_time: {
                type: "string",
                label: "创建时间",
                tableOption: {},
                searchOption: {
                    comType: "dateRange",
                },
            },
        },
    },
    tableConfig: {
        headerButtons: [
            {
                label: "新增商品",
                eventKey: "showComponent",
                type: "primary",
                plain: true,
            },
        ],
        rowButtons: [
            {
                label: "修改",
                eventKey: "showComponent",
                type: "warning",
            },
            {
                label: "删除",
                eventKey: "remove",
                eventOption: {
                    params: {
                        product_id: "schema::product_id",
                    },
                },
                type: "danger",
            },
        ],
    },
},

123.png

如图所示,我通过上述配置直接生成出了一个页面,配置的 key 有:product_id(商品 ID)、product_name(商品名称)、price(商品价格)、inventory(库存)、create_time(创建时间)在各自的 tableOption、searchOption 中配置了他们在 el-table 以及 search-bar 的展示状态。

结语

通过本文的介绍,相信您对DSL和低代码平台已经有了初步的了解。它们不仅能够帮助企业提高开发效率,还能让业务人员更好地参与到应用开发过程中,真正实现“人人都是开发者”的愿景。