likes
comments
collection
share

如何从无到有搭建一套完整的低代码平台(三)通用组件库的配置

作者站长头像
站长
· 阅读数 32

一. 介绍

上一节设计了一下client的基本配置。选用vite + ts + vue3.0搭建前端核心,有兴趣的同学可以移步去看一下上期的内容。接下来我们继续按部就班的实现一下接下来的功能。

二. client总览

1. 基本布局

简单看一下市面上的成熟低代码平台,他们的desgin页面的基本布局

如何从无到有搭建一套完整的低代码平台(三)通用组件库的配置

不看其他的功能,主要就是左边为可选择组件(原子组件)、中间是一个design的画布、右侧是选中每个组件的属性配置面板。

我们可以得出结论, 对于一个低代码平台的页面design部分,主要是三个要素。

  • 原子组件
  • 页面布局
  • 单组件属性配置面板

如何从无到有搭建一套完整的低代码平台(三)通用组件库的配置

实现这三个部分是最重要的。我们先来实现一下原子组件。

三. 通用可配置组件库

1. UI库

根据风格喜好和使用习惯来说,我这边选择element的牛逼plus版本,支持vue3.0 官网地址

这里要注意的一点是,不要直接在client项目中安装element-plus,我这边考虑的是单独建一个UI包,因为之后不仅仅是单独使用现有的element-plus的组件,还会对其进行二次封装。而且也希望原子组件和业务组件分开。 ok,我们开始!

cd packages && cd commonUI

    pnpm add element-plus

官方提供了完整引入和手动引入的形式。考虑到原子组件的组合问题,这边采用手动引入的方式

这里以Button组件为例:

新建 src/Button/index.ts

    import { ElButton } from 'element-plus';
    import 'element-plus/es/components/button/style/css';
    export default ElButton;

单组件手动引入的时候一定要注意一下手动引入css样式

新建src/index.ts

    import ElButton from './BUtton/index';
    
    export {
        ElButton
    }

修改一下package.json文件:

      "main": "./src/index.ts",
       "type": "module"

这样我们完成了一个基本组件的配置和导出。

回到client中:在第一篇中我们对packages里面的包都做了互相依赖。所以这里可以直接引用

在client的app.vue文件中引入

    <template>
      <div class="box">
          <h1>lowCode</h1>
          <ElButton>Default</ElButton>
      </div>
    </template>

    <script lang="ts" setup>
    import { ElButton } from '@six-membered/ui';
    </script>

    <style lang="less" scoped>
    @import url('./index.less');
    </style>

打开页面:

如何从无到有搭建一套完整的低代码平台(三)通用组件库的配置

可以看到button已经被引用进来

2. 自动组件生成

看一下Button/index.ts文件,发现,其实所有从element-plus导出的组件,都可以采用这种方式引入,而且引入的配置代码及其相似。那我们是不是可以写个脚本,批次生成这样的组件,不用在手动一个个写啦!(这里先不考虑组合以及二次组件扩展的问题

其实也很简单,就是通过node的fs模块,向文件目录中写入对应的文件。然后做一下异常处理即可。

file-save 市面上比较火的创建文件和写入文件的API。

如何从无到有搭建一套完整的低代码平台(三)通用组件库的配置

file-save 有个好处就是可以接受链式调用。这样的话给我们提供了极大的便利!

简单试一下:

向commonUI根目录写入一个文件

新建builder/bin.js

    const fileSave = require('file-save');

    const template = `
    import { ElButton } from 'element-plus';
    export {
        ElButton
    }
    `
    fileSave('./test.ts')
        .write(template, 'utf-8')
        .end('\n')
        .finish(() => {
            console.log('写入文件完成!')
        })

向根目录的test.ts文件写入模版内容(有test.ts直接写入,没有创建)

在终端执行一下:

如何从无到有搭建一套完整的低代码平台(三)通用组件库的配置

在根目录上生成了一个新的test.ts文件

如何从无到有搭建一套完整的低代码平台(三)通用组件库的配置

OK,接下来就好办了,我们维护一个json文件,通过读取这个json文件的配置自动生成对应的目录。 在commonUI的根目录下新建 components.json,这里保存着组件的名称和在目录下的文件路径。

    {
        "Button": "./src/Button/index.ts",
        "Card": "./src/Card/index.ts",
        "Dialog": "./src/Dialog/index.ts",
        "ButtonGroup": "./src/ButtonGroup/index.ts"
        ...
    }

在bin.js中读取一下:

    const fileSave = require('file-save');
    const componentsMap = require('../components.json');

思考一个问题,既然要批量生成,那肯定要有个模版,根据之前的Button/index.ts我们不难看出,这个模版作为生成每个组件里面的内容,需要接受两个参数

  • 组件名称
  • 组件路径

OK,那我们实现一下模版。

在builder目录下新建template.js:

function getTemplate(variable) {
const { name } = variable;
function setComponentTemplate() {
return `
import { El${name} } from 'element-plus';
import 'element-plus/es/components/${name.toLowerCase()}/style/css'

export default El${name};
`
}

}

return {
    setComponentTemplate
}
}

module.exports = getTemplate;

这里要注意几个问题

  • template模版顶格写,避免生成出来的js代码有空行,会导致代码较乱。
  • name.toLowerCase()是有问题的,因为有些组件的样式引入的路径不是这样。

如何从无到有搭建一套完整的低代码平台(三)通用组件库的配置

比如这个breadcrumb-item就不是采用这样的引入方式。 这里需要做一下文件名称的处理,放在最后实现。

回到bin.js里面,导入这个模版。

但是要注意一下的是,需要单独定义一个readTemplate,因为最后要单独生成一下index.ts。

// 需要累积组合import和export,执行一次,去替换之前的结果
import El${name} from './${name}/index';

export {
    ${name}
}
const fileSave = require('file-save');
const componentsMap = require('../components.json');
const fileTemplateFuntion = require('./template');

// 这里单独定义一个readTemplate,因为最后要单独生成一下index.ts
// import和export单独处理
let readTemplate = {
    import: '',
    export: ''
}

for (let key in componentsMap) {
// 遍历一下componentsMap, 累积生成readTemplate(先生成,不写入文件中)
// 在生成readTemplate的同时,循环生成单组件对应的文件。
    const getComponentTemplate = fileTemplateFuntion({ name: key }).setComponentTemplate();
    readTemplate.import += `import El${key} from './${key}/index';\n`;
    readTemplate.export += `  El${key},\n`;

    fileSave(componentsMap[key])
    .write(getComponentTemplate, 'utf-8')
    .end('\n')

}

// 重新定义一个render模版,拼接成需要渲染的模块,写入文件中。
const renderTemplate = `
${readTemplate.import}
export {
${readTemplate.export}
}
`

// 文件写入
fileSave('./src/index.ts')
.write(renderTemplate, 'utf-8')
.end('\n')

OK,这里一个模版的渲染就完成了。我们在package.json里面修改一下启动命令:


"scripts": {
    "ui:create": "node builder/bin.js"
  }

然后 pnpm run ui:create

看一下现在的文件目录:

如何从无到有搭建一套完整的低代码平台(三)通用组件库的配置

根据components.json生成对应的文件。还是比较节省时间和金钱的有么有!!

3. 修改配置组件名称

之前我们提到了这个问题,不是所有组件的样式都是按照button、card这样的方式引入的,所以我们这里要做一个补丁去修复一下这个问题。

去到element-plus源码里面看一下目录结构:

如何从无到有搭建一套完整的低代码平台(三)通用组件库的配置

可以看出来,文件的名称就是style样式引入的名称。转化一下就是对应的组件名称。 转换有两种规则:

  • 带'-'连接的,比如breadcrumb-item文件名被转换为ElBreadcrumbItem
  • 不带'-'的。比如button、dialog 文件名被转换为ElButton、ElDialog

OK,那就以element-plus/es/components/** 里面的文件名称作为components.json里面的配置文件写法

修改一下components.json:

    {
   "button": "./src/Button/index.ts",
   "card": "./src/Card/index.ts",
   "dialog": "./src/Dialog/index.ts",
   "button-group": "./src/ButtonGroup/index.ts"
}

新建一个uppercaseAndLowercase.js:

    function upperCase(char) {
        if (!char.length) return;
        // 通过replace把首字母替换为大写
        return char.replace(char.charAt(0), char.charAt(0).toUpperCase());
    }

    function upperCaseAndCharacters(char) {
        if (char.includes('-')) {
             // 把`-`分割,然后对生成的数组每一项单独进行首字母大写替换
            const _char = char.split('-');
            return _char.reduce((prev, current) => {
                return prev += upperCase(current)
            }, "")
        }
        else {
           return upperCase(char);
        }
    }

    module.exports = {
        upperCase,
        upperCaseAndCharacters
    }

可以简单做个测试:

如何从无到有搭建一套完整的低代码平台(三)通用组件库的配置

目前看起来没有什么问题。

下一步,我们对模版template.js和bin.js进行改造:

  • template.js
function getTemplate(variable) {
// 在加一个处理好的参数,还是需要保留components.json里面的name,这个是引入style的路径
const { name, transformName } = variable;
function setComponentTemplate() {
return `
import { El${transformName} } from 'element-plus';
import 'element-plus/es/components/${name}/style/css'

export default El${transformName};
`
}

return {
    setComponentTemplate
}
}

module.exports = getTemplate;

最终写入的模版有两种:

  • 第一种:
    import { ElButton } from 'element-plus';
    import 'element-plus/es/components/Button/style/css'
    
    export default ElButton;

  • 第二种:
    import { ElButtonGroup } from 'element-plus';
    import 'element-plus/es/components/button-group/style/css'

    export default ElButtonGroup;
  • bin.js

const fileSave = require('file-save');
const componentsMap = require('../components.json');
const fileTemplateFuntion = require('./template');
const { upperCaseAndCharacters } = require('./uppercaseAndLowercase');

let readTemplate = {
    import: '',
    export: ''
}

for (let key in componentsMap) {
    // 对参数进行处理一下,转成我们想要的格式
    const _key = `${upperCaseAndCharacters(key)}`;
    const getComponentTemplate = fileTemplateFuntion({ name: key, transformName: _key}).setComponentTemplate();
    readTemplate.import += `import El${_key} from './${_key}/index';\n`;
    readTemplate.export += `  El${_key},\n`;

    fileSave(componentsMap[key])
    .write(getComponentTemplate, 'utf-8')
    .end('\n')

}

const renderTemplate = `
${readTemplate.import}
export {
${readTemplate.export}
}
`

fileSave('./src/index.ts')
.write(renderTemplate, 'utf-8')
.end('\n')

ok,现在在components.json中增加几项来试试。

  • components.json
    {
       "button": "./src/Button/index.ts",
       "card": "./src/Card/index.ts",
       "dialog": "./src/Dialog/index.ts",
       "button-group": "./src/ButtonGroup/index.ts",
       "dropdown": "./src/Dropdown/index.ts",
       "dropdown-item": "./src/DropdownItem/index.ts",
       "dropdown-menu": "./src/DropdownMenu/index.ts"
    }

pnpm run ui:create

现在看一下目录结构

如何从无到有搭建一套完整的低代码平台(三)通用组件库的配置

正好就是我想要的效果!那么我们在client里面使用一下试试

回到client目录: app.vue,从官网copy一下下拉菜单的案例,稍微修改一下。

    <template>
      <div class="box">
          <h1>lowCode</h1>
          <ElButton>Default</ElButton>

        <ElDropdown>
          <span class="el-dropdown-link">
            Dropdown List
          </span>
          <template #dropdown>
            <ElDropdownMenu>
              <ElDropdownItem>Action 1</ElDropdownItem>
              <ElDropdownItem>Action 2</ElDropdownItem>
              <ElDropdownItem>Action 3</ElDropdownItem>
              <ElDropdownItem disabled>Action 4</ElDropdownItem>
            </ElDropdownMenu>
          </template>
      </ElDropdown>
      </div>
    </template>

    <script lang="ts" setup>
    import { ElButton, ElDropdown, ElDropdownItem, ElDropdownMenu } from '@six-membered/ui';
    </script>

    <style lang="less" scoped>
    @import url('./index.less');
    </style>

项目启动一下:

如何从无到有搭建一套完整的低代码平台(三)通用组件库的配置

可以看到dropdown已经被加载进来了。

真nice!!

三. 结尾

基本组件库配置什么的就算完成了,接下来继续实现别的。有兴趣的同学可以点一波关注哦!!!感谢🙏

参考文章:

element-plus官网

往期文章:

转载自:https://juejin.cn/post/7270916734138990592
评论
请登录