Corgi-ICode —— 帮你少写点代码

前言

Corgi-ICode

制作起因:

在维护类似的管理后台时,总会做一些相似的页面,复制出来之后又要修改、删除等等,很是麻烦呢。

0

后来我写了一个脚本,通过写入一些配置数据,直接通过node编译成vue文件,使用起来倒也,但有缺点就是经常会忘记一些属性,导致经常要翻组件文档。因此打算做一个可视化的编辑器来生成模板。


Corgi-ICode

页面设计和常规的低代码平台类似,左侧是一些组件和模板,中间是拖拽面板,右边是配置面板可以配置选中组件的一些属性、数据。

但区别在于,这个项目只会生成对应的Vue SFC代码,把生成的代码当作页面的基础模板再做后续的业务开发。

涉及到的技术:Vue3ViteElement-plusmonaco-editorvuedraggable

源码地址

在线体验

项目结构

拖拽功能
组件工具
导入组件库
编译
数据维护
历史记录
组件库
一个组件
组件实例
代码模板
配置列表
Packages
UI
Core
Component
DraggableArea
HandleComp
App
Import
Complie
widgetList
historyWidgetList
Element-plus
Input
InputVue
Templates
Options

首先,UI层与组件库并不关联,通过调用Core中的import功能去加载组件库的数据,加载出的数据都维护在Core中,UI引用这些数据进行页面渲染(组件列表、模板列表、组件配置表等),凡是会对主数据造成影响的功能都需要到Core中调用。

Core中维护了操作主要数据的方法以及公用组件,比如 DraggableArea 功能组件,除了UI中的操作区域需要拖拽外,组件库中的FormGridCard等组件也都需要有内部的拖拽功能。

最后组件库,由于UI与组件库并不关联,所以理论上可以兼容Vue3的各种组件库,但由于工作量太大,现在只做了Element-plus

拖拽功能

这里使用了vue.draggable.next来做拖拽功能。

由于是B端项目,没有复杂的页面排版,不需要定位之类的操作,所以只需要维护一个List,并编写一个用于渲染组件的高阶组件即可。

<!-- 组件菜单 -->
<el-collapse-item
  v-for="item in menu"
  :key="item.title"
  :title="item.title"
  :name="item.title"
>
  <draggable
    :list="item.children"
    item-key="type"
    :sort="false"
    :clone="cloneNewWidget"
    :group="{ name: 'dragGroup', pull: 'clone', put: false }"
    class="flex justify-between flex-wrap"
  >
    <template #item="{ element }">
      <div>
        {{ element.title }}
      </div>
     </template>
   </draggable>
</el-collapse-item>

在菜单中调用clone钩子,为拖拽中的组件配置一个唯一的Key,方便之后的组件操作。

 <!-- 操作面板 -->
<draggable
  :list="list"
  handle=".moveArea"
  ghost-class="ghostClass"
  item-key="key"
  group="dragGroup"
  @add="addEnd"
>
  <template v-if="!list.length" #footer>
    <div class="text-center opacity-60 h-40 leading-40">
      {{ empty || '拖拽区域' }}
    </div>
  </template>

  <template #item="{ element }">
    <HandleComp :item="element">
      <slot :item="element" />b
    </HandleComp>
  </template>
</draggable>

在拖拽结束后触发事件add,此时就可以拖拽更新后的组件列表全部打上父级的Key,建立父子关系也是方便后续的维护工作。同时也可以进行历史记录的操作,在拖拽完成后在历史记录的List中插入一条新的数据。

结构设计

类似于常规的低代码平台,拖拽、配置完成之后都需要导出一串JSON数据,用于渲染和编译。

// 单个
export interface IWidgetItem {
  title: string // 标题
  type: string // 组件类型
  icon?: FunctionalComponent<SVGAttributes, {}>
  component?: string // 调用组件名称
  key: string // 自动生成的key
  form: IWidgetItemForm // 属性配置
  noForm?: boolean // 是否为form下组件
  children?: IWidgetItem[]
  parent?: string
  validateFn?: Function // 表单组件校验方法
  updateDataFn?: () => void // 用来更新组件内的数据
}

export type IWidgetItemForm = Record<
  string,
  {
    label: string // 名称
    type: keyof typeof IWidgetOptions // 输入组件
    value: any
    isShow?: (options: any) => boolean
    changeCb?: (options: any) => void
  }
>

组件方面定义了其自身的typekeychildren等字段,而对于属性的配置方面,在UI层中创建了如InputSelectCode等用于不同场景的属性配置的输入组件,在一个组件被拖入拖拽面板之后,右侧的配置栏会取得当前活跃组件的form属性配置表,根据每一条属性的type匹配到对应的输入组件,然后再进行每条属性的组件渲染。

组件库加载到的组件配置表在这里插入图片描述

input的配置面板在这里插入图片描述

右侧配置面板中每条属性的改动都需要记录到属性的value字段,同时会体现在拖拽面板中。

将每个必要属性配置完成后就会得到一条IWidgetItem[]形式的数据。

在这里插入图片描述

模板编译

IWidgetItem[]进行遍历,通过每一个组件的组件名找到预先在组件库中编写好的编译函数,传入配置的属性值、表单属性等信息,生成模板数据

/**
 * 编译函数
 * options:配置的属性
 * formDataName:父级form 的key
 */
export type renderWidgetCode = (options: Record<string, any>, formDataName?: string) => {
  template: string | ((arg: string) => string)  // 代码模板
  formData?: Record<string, any>                // 该组件内用到的formData字段
  privateVar?: Record<string, any>              // 组件内的私有变量
  formDataName?: string                         // 父级form 的key
  importList?: Record<string, any>              // 组件内的引入列表
  componentName?: string                        // 子组件名称
  componentTemplate?: string                    // 子组件的模板
  endScript?: string                            // 其他代码 hooks等
}
const run: renderWidgetCode = (options, _formDataName) => {
  const attrs = [
    'type',
    'placeholder',
    'clearable',
    'maxlength',
    'minlength',
    'showWordLimit',
  ]
  const attrsStr = attrs
    .map(attr => formatArrt(attr, options[attr]))
    .filter(Boolean)
    .join(' ')

  return {
    formData: {
      [options._key]: options.value,
    },
    template: `<el-form-item label="${options.label}" prop="${options._key}">
    <el-input ${_formDataName ? `v-model="${_formDataName}.${options._key} "` : ''}${attrsStr} />
    </el-form-item>
    `,
  }
}

之后就是将各个组件所生成的数据结果进行混合,最终都生成String拼装在一起。

const baseTemplate = `
    <template>
      ${templateStr}
    </template>
    
    <script setup>
    ${importListStr + formDataStr + validateListStr + widgetVariableStr + endScript}
    </script>
  `

写在最后

本项目的初衷就是做一个简单的可视化的代码模板编辑器,所以最后生成的代码会比较简陋,还需要后续再进行弥补。

如果真要做成低代码的形式还需要后台的支持,编写更多更完整的组件。(但是我真的不喜欢低代码)

因为项目是用Vue3写的,所以最后生成的代码是Vue3 setup形式的,而作者本人在公司维护的一直是Vue2 Options形式的代码,所以这个工具也用不上😂,只能当个练手的玩具。

如果真的有需要的话,我也会尽量维护👌。

源码地址

在线体验

参考项目

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值