# low-code **Repository Path**: turn-into-an-island/low-code ## Basic Information - **Project Name**: low-code - **Description**: 青训营低代码案例 - **Primary Language**: JavaScript - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2022-07-25 - **Last Updated**: 2023-03-20 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README 一、项目介绍 低代码平台项目核心信息:本项目旨在开发一个供运营、产品快速搭建网站的可视化平台,利用可视化的拖拽与属性配置完成构建和日常运营,而开发只进行平台的维护、业务组件的新增和迭代。 项目服务地址-必须:http://116.62.226.254/ gitee地址:low-code: 青训营低代码学习案例,仅供学习 (gitee.com) 二、项目分工 团队成员 主要贡献 王盈 物料区与相应属性配置等 薛彬 项目拖拽搭建平台等 汪文松 无 谭晶 无 田诗圆 无 三、项目实现 3.1 技术选型与相关开发文档 Vue3+Sass+jsx+Webpack 选择Vue的考虑: 体积小,复杂度低 Vue 的体积小,网络性能角度相比 React 更适合移动端 移动端一般巨型项目很少,从代码结构上来讲,使用 Vue 实现更符合我们的场景复杂度, React 更适合大型相对更复杂的 SPA 上手成本和迁移成本低 Vue 的学习和上手成本相对更低,团队成员对于 Vue 的认可度和热情也比较高 组件内双向绑定、数据依赖收集 组件内支持双向绑定,更方便的去进行组件内的数据响应与交互 独有的数据依赖收集模式使其默认的数据响应和渲染效率都要比 React 高一些 组件库: Element Plus 统一规范: 主要就是操作json配置文件;渲染区 使用json文件动态渲染成对应的组件 { "label": "button", "icon": "icon-button", props: { "text":... "type":... "size":... } } [图片] 属性控制面板生成过程 进阶方式解耦、工业化,这样才能在后面使大量组件接入平台。然而有一个风险点「JSON是无规则的」,组件描述JSON应该「按平台定的规则」来写「平台才能识别」,所以我们需要用规则来标准化JSON。 解决办法就是通过JSON Schema协议来约束JSON,让它根据我们定的标准来编写。 「Schema协议」,是我们「平台规范」的工具,也就是我们可视化开发平台的核心。 3.2 架构设计 可视化搭建平台主要有三块: - 项目拖拽搭建平台的构建 - 物料接入平台流水线的构建 - 属性配置区的构建 [图片] 3.3 项目代码介绍 组件结构 schema,一种 JSON 数据结构,我用于描述画布信息,以及画布中拖拽添加的组件元素信息。这里我们使用到了画布的宽高信息,在 schema JSON 中结构如下: { "container": { "width": ... "height": ... }, "blocks": [ // 画布中拖拽的元素集合,下面介绍 ] } 基本上 组件设计包含以下3个部分组件: 1、component 组件主体 2、schema 组件的DSL,结构协议层 3、render里的定义了组件的类型、外观、从属关系,后期考虑纳入schema registerConfig.register({ label: '按钮', resize: { width: true, height: true }, preview: () => , render: ({ props, size }) => {props.text || '渲染按钮'}, key: 'button', props: { text: createInputProp('按钮内容'), type: createSelectProp('按钮类型', [ { label: 'primary', value: 'primary' }, { label: 'success', value: 'success' }, { label: 'warning', value: 'warning' }, { label: 'danger', value: 'danger' }, ]), size: createSelectProp('按钮尺寸', [ { label: '默认', value: '' }, { label: '大', value: 'large' }, { label: '小', value: 'small' }, ]) } }) 我们只需要按照上面的方式编写组件即可,props是定义的数据层,用来控制组件的shape,也就是组件的表现。 function createEditorConfig() { const componentList = []; const componentMap = {} return { componentList, componentMap, register: (component) => { componentList.push(component); componentMap[component.key] = component; } } } 两个关键变量: - componentList: 物料组件的集合,用于渲染编辑器左侧物料的数据源; - componentMap: 是一个 map 映射关系,根据 type 字段进行映射,有了它,就可以在画布中通过 Schema 数据去匹配物料组件来渲染画布视图。 有了数据,我们就可以通过 map 渲染左侧区物料组件: ...... if (component && component.props) { content.push(Object.entries(component.props).map(([propName, propConfig]) => { return .... }[propConfig.type]()} })) } if(component && component.model){ content.push(Object.entries(component.model).map(([modelName,label])=>{ return {} })) } } editData表示组件的可编辑属性, 我们可以自定义哪些组件可编辑. propConfig为组件接收的属性, 和editData数组项中的key一一对应. 1、关于辅助线: 当画布中存在两个或多个 block,拖动其中一个 block 至另一个 block(参照物)周围时,能够显示出上下,或者居中的参考线,便于对两个 block 进行对齐排版。 2、关于吸附: 当拖动 block 的移动位置非常接近另一个 block 的位置时(比如两个 block 的相差距离 < 5px),能够直接让它们紧挨在一起(吸附),而非手动去拖动实现精准对齐。这是一个很好的体验! 思路 辅助线显示的规则是拿选中的 blocks 与其余未选中的 blocks,在拖动移动过程中进行位置比对。 在拖动一个或多个 block(focus blocks)前,画布上其余的 block(unfocused blocks)需要提供自身周围的参考线(即辅助线,下文中的 lines); 每次拖动 focus blocks 时,会根据当前移动到的位置,与 unfocused blocks 提供的辅助线集合(lines)中的位置进行比较,若满足临近条件,显示其辅助线; 每一个 unfocused blocks 周围都可能存在10种辅助线,横向、纵向分别各5条。 定义 Hooks 这里需要用到两个 Hook: - selectIndex:记录当前选中拖动的 block 索引; - markLine:记录水平、垂直辅助线显示的位置,因为涉及到视图更新 const selectIndex = ref(-1); let markLine = reactive({ x: null, y: null }) 菜单功能: 删除,导出json,导入json,置顶,置后,关闭(发布),预览。 后端 spring-boot 用户登录接口 - `POST` /api/login | 参数名 | 是否必选 | 类型 | 说明 | | ------------- |:-------------:|:-----:| -------------:| | username | true | string | 用户名 | | password | true | string | 密码 | 返回示例 { "code": 1, "msg": "登录成功", "data": "" } - `GET` /api/register | 参数名 | 是否必选 | 类型 | 说明 | | ------------- |:-------------:|:-----:| -------------:| | username | true | string | 用户名 | | password | true | string | 密码 | { "code": 0, "msg": "注册失败", "data": "用户已存在" } 未完成的 ## 模版管理 ### 获取模版库 - `GET` /api/tpls/free 返回示例 ``` json { "state": 200, "result": [ { "img": "http://xxx/uploads/", "name": "合作模版", "tid": "B73349B6" } ] } ``` ### 保存模版 - `POST` /api/tpl/save 先决条件: - 用户已登陆 | 参数名 | 是否必选 | 类型 | 说明 | | ------------- |:-------------:|:-----:| -------------:| | name | true | string | 模版名称 | | cate | true | string | 模版分类 | | img | false | string | 模版封面图 | | tpl | true | array | 模版数据 | | pageConfig | false | object | 模版全局配置 | 返回示例 ``` json { "state": 200, "result": { "tid": "" }, "msg": "保存成功" } ``` ### 删除模版 - `DELETE` /api/tpl/del 先决条件: - 用户已登陆 | 参数名 | 是否必选 | 类型 | 说明 | | ------------- |:-------------:|:-----:| -------------:| | tid | true | string | H5模版id | 返回示例 ``` json { "state": 200, "result": null, "msg": "删除成功" } ``` ## 文件上传 - `POST` /files/upload/free 先决条件: - 用户已登陆 | 参数名 | 是否必选 | 类型 | 说明 | | ------------- |:-------------:|:-----:| -------------:| | File | true | File | 文件对象 | 返回示例 ``` json { "state": 200, "result": { "filename": "", "url": "", "size": }, "msg": "文件上传成功" } ``` 四、测试结果 建议从功能测试和性能测试两部分分析,其中功能测试补充测试用例,性能测试补充性能分析报告、可优化点等内容。 待完善Vitest 五、Demo 演示视频 (必填) 暂时无法在飞书文档外展示此内容 六、项目总结与反思 1. 目前仍存在的问题 项目后端很多未完成,用户自定义组件或者是嵌套组件较难实现。 2. 已识别出的优化项 1.优化了编辑器拖拽移动体验:实现辅助线和吸附功能 2图片懒加载 3支持鼠标快捷键操作 3. 架构演进的可能性 4. 项目过程中的反思与总结 团队确实协作出现问题,后端接触时间太短,还离开了几个,由于时间问题,导致项目有些功能没有实现,之后我们会继续学习,提高自身的能力。 七、其他补充资料(选填)