青训营之旅眼看就要结束了
这是我参与「第四届青训营 」笔记创作活动的第13天
- 做一个总结吧
- 我们队选择做的项目是lowCode低代码平台,对于我而言是第一次接触也是第一次知道还有这样的平台存在,整体的逻辑与平时接触到的例如后台管理平台,商城等逻辑是不一样的
- 目前项目的状态是功能相对完整而又存在较大优化,扩展空间
- 先放一下相关链接吧
项目的上线地址
项目的GitHub链接
npm地址链接
开发文档
一、项目情况
-
GitHub统计
- 项目从7月24号开工,目前截止于8月24号,我差不多在8月份初开始参与开发
- 项目总commit次数
- 项目从7月24号开工,目前截止于8月24号,我差不多在8月份初开始参与开发
-
项目分工 团队成员 | 主要贡献 | | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | | 杨文锋 | 负责项目技术选型,负责基础架构构建,负责整体基本流程搭建,负责部分基础字段的实现,负责组件的事件属性配置流程,搭建负责扩展组件的事件属性 | | 陈立婷 | 负责项目模块,功能的扩展在物料方面进一步搭建了实现流程,实现了全部容器和高级组件以及部分基础组件,部分模板板块;在画布方面实现了对画布的导出预览导出表单数据等功能;在属性设置方面增设了全局属性的设置;整体实现了动态logo和主题切换;负责将项目打包上线;负责编写简易使用文档;负责将预览部分插件化,上传至npm | | 谢祥辉 | 负责部分组件样式实现,基本属性编写,元数据配置 | | 叶晓娟 | 负责基础属性和样式属性的实现,添加部分组件的基本字段。
-
我在项目中的具体进度
二、项目逻辑
- 通过
pinia管理画布状态,由左侧字段拖拽面板,中间画布面板和右侧属性配置面板共同操控画布全局状态实现整个低代码平台核心运行逻辑 - 拖拽通过
vuedraggable库实现,在拖拽的时候通过修改画布全局状态实现元素拖拽进入画布、调整在画布区域的位置、从画布中移出等交互逻辑 - 通过watch观察容器的子容器数目,动态修改
chidlren的数组结构,从而实现容器嵌套容器 - 通过
ts文件配置相关组件渲染在左边拖拽面板的样式和在画布的样式,通过componentIS动态渲染组件 - 通过
type字段区分不同类型字段的渲染方式 - 通过
pinia管理表单数据,主题切换 - 通过抽取除去
draggable以及点击与删除相关代码实现无干扰的预览功能
三、项目遇到的一些小bug
1、JSON.stringify会丢失函数,但是我们导出的JSON代码是包含函数的
- 导入导出采用了
JSON.stringify和JSON.parse进行转化
- 而
JSON.stringify是会丢失函数内容的,导致导出的JSON丢失了eventHandlerGenerator函数,如果直接采用导出的JSON进行导入则会报错(找不到e.eventHandlerGenerator)
- 解决方法:在
JSON.stringify和JSON.parse的基础上再封装
// 对象序列化,undefined和函数丢失问题
export const JSONStringify = (option: any) => {
return JSON.stringify(
option,
(key, val) => {
// 处理函数丢失问题
if (typeof val === 'function') {
return `${val}`
}
return val
},
2,
)
}
// 对象序列化解析
export const JSONParse = (objStr: any) => {
return JSON.parse(objStr, (k, v) => {
//打包前代码为(code) => .... ,打包后代码为code=>...
if (
typeof v === 'string' &&
v.indexOf &&
(v.indexOf('(code) =>') > -1 || v.indexOf('code=>') > -1)
) {
// eval 可能在eslint中报错,需要加入下行注释
// eslint-disable-next-line
return eval(`(function(){return ${v}})()`)
}
return v
})
}
2、采用histrory路由模式,打包上线后刷新会显示404NotFound
- 应用是单页客户端应用,当使用
history模式时,URL就像正常的url,可以直接访问www.xxx.com/index ,但是因为vue-router设置的路径不是真实存在的路径,所以刷新就会返回404错误 - 解决方法:
- 方法一:改为hash模式(我比较懒就直接改回了hash)
export default function setupRouter(app: App) { const router = createRouter({ history: createWebHashHistory(), routes, }) app.use(router) } - 方法二:在宝塔面板的配置文件中添加如下:
添加上这个配置 location / { try_files $uri $uri/ @router; index index.html; } location @router { rewrite ^.*$ /index.html last; }
- 方法一:改为hash模式(我比较懒就直接改回了hash)
3、因增加容器组件导致的点击拖拽,删除功能失效
- 因为组件和容器可以一直嵌套,所以不能利用遍历而是利用递归
- 因为children还存在两种结构
- 对于flex和grid,tab,collapse容器因为还可以分成多个容器,故children为二维数组
- 而表单和表单项的children为一维数组
//找到点击的target组件,list为当前页面的json数据,id为点击的组件id
export const getTarget = (list: any, id: string): any => {
for (let o of list) {
if (o.id == id) return o
if (o.children) {
//children为二维数组
if (o.children[0] instanceof Array) {
for (let item of o.children) {
const o_ = getTarget(item, id)
if (o_) return o_
}
} else {
//children为一维
const o_ = getTarget(o.children, id)
if (o_) return o_
}
}
}
}
//使用filter删除要删除的id
export const recurFilter = (arr: any, id: string) => {
return arr.filter((item: any) => {
if (item.id == id) {
return false
}
//flex,gird,collapse的children是二维数组
if (item.children && item.children[0] instanceof Array) {
for (let i = 0; i < item.children.length; i++) {
item.children[i] = recurFilter(item.children[i], id)
}
}
//表单,表单项的children是一维数组
if (item.children && !(item.children[0] instanceof Array)) {
item.children = recurFilter(item.children, id)
}
return true
})
}