首页 > 其他分享 >Gitee千Star优质项目解析: ng-form-element低开引擎解析

Gitee千Star优质项目解析: ng-form-element低开引擎解析

时间:2024-05-14 20:53:18浏览次数:26  
标签:vue false form labelWidth items 组件 Star 解析 type

好家伙,

在写项目的时候,我发现自己的平台的组件写的实在是太难看了,于是想去gitee上偷点东西,于是我们本期的受害者出现了

gitee项目地址

https://gitee.com/jjxliu306/ng-form-elementplus-sample.git

组件库以及引擎完全开源,非常牛逼的项目,非常牛逼的作者

 

项目名:ng-form-element

整体的布局,组件样式,编辑器模板,组件拖动时的过渡动画,都写的非常漂亮,(比我写的好看多了)

于是我决定,扒一下他的内裤,学习(抄袭)一下

 

0.项目解析

官方文档:NG-FORM

于是我们快速定位到引擎部分

 

1.开始分析

我们知道,低开的引擎做的事无非是

  把数据

  变成视图

 

我们先来找数据

数据部分

//packages/index.vue

  data() {
    return {
      selectItem: {},
      arrow: false,
      i18nkey: getUUID(),
      formTemplate: this.template || {
              list: [
              ],
              config: {
                labelPosition: 'left',
                labelWidth: 100,
                size: 'mini',
                outputHidden: true, //  是否输出隐藏字段的值 默认打开,所有字段都输出
                hideRequiredMark: false,
                syncLabelRequired: false,
                labelSuffix: '' , // 标签后缀
                customStyle: ''
              }
            },
    }
  },
  props: {
    template: {
      type: Object,
      default: () => {
        return {
          list: [],
          config: {
            labelPosition: 'top',
            labelWidth: 80,
            size: 'mini',
            outputHidden: true, //  是否输出隐藏字段的值 默认打开,所有字段都输出
            hideRequiredMark: false,
            syncLabelRequired: false,
            labelSuffix: '' , // 标签后缀
            customStyle: ''
          }
        }
      }
    },

 

然后来找视图部分

//packages/index.vue

<ContainerPanel
              :formTemplate="formTemplate"
              @handleSelectItem="handleSelectItem"
              :selectItem="selectItem"
              :arrow="arrow"
          >
          </ContainerPanel>

import ContainerPanel from './panel-container/index.vue'
  1. :formTemplate:传模板数据的

  2. @handleSelectItem:这是一个事件处理器,当组件内的 handleSelectItem 方法被触发时,会执行传入的回调函数。handleSelectItem 是组件内部定义的事件处理函数名。

  3. :selectItem:这是绑定的数据属性,用于传递一个"被选中的数据"

  4. :arrow:暂时没看出来干嘛的

 

//packages/panel-container/index.vue
<el-form  
          :label-width="formTemplate.config.labelWidth + 'px'" 
          class="ng-form"
          :label-position="formTemplate.config.labelPosition"
          :hide-required-asterisk="formTemplate.config.hideRequiredMark" 
          :label-suffix="formTemplate.config.labelSuffix"
          ref="form" 
          :style="formTemplate.config.customStyle" 
          :size="formTemplate.config.size"
        >
        <el-row :gutter="20" class="row"> 
                <draggable  
                    tag="div"
                    class="draggable-box"
                    v-bind="{
                      group: 'form-draggable',
                      ghostClass: 'moving',
                      animation: 180,
                      handle: '.drag-move'
                    }"
                    :force-fallback="true"
                    v-model="formTemplate.list" 
                    @add="dragEnd($event, formTemplate.list)" 
                      >
                    <transition-group tag="div" name="list" class="items-main"> 
                        <Node  
                                :class="{'drag-move' : record.drag_ == undefined || record.drag_  }"
                                v-for="record in formTemplate.list"
                            :key="record.key"
                            :record="record"
                            :isDrag="true"
                            :config="formTemplate.config"
                            :selectItem="selectItem"
                            @handleSelectItem="handleSelectItem"
                            @handleCopy="handleCopy(record)"
                            @handleDetele="handleDetele(record)"
                            >  
                        
                        </Node> 
                    </transition-group>
                </draggable> 
         
        </el-row> 
    </el-form> 
import Item from '../items/index.vue'

 

  1. <transition-group> 是 Vue.js 的内置过渡组件,用于给列表添加过渡效果。

  2. el-form的作用我们后面说
//packages/form-design/items/index.vue
<template>    
  <ItemNode 
    v-if="isLayout"
    :record="record"
    :disabled="disabled" 
    :preview="preview"
    :isDragPanel="isDragPanel"
    :prop-prepend="propPrepend"
    :selectItem="selectItem" 
    :style="{'display': recordVisible ? '' : 'none'}"
    :models="models" 
    @handleSelectItem="handleSelectItem" 
    >
      <!-- 递归传递插槽!!! -->
      <template v-for="slot in Object.keys($slots)"  :slot="slot">
        <slot :name="slot" :record="record"/>
      </template>
    </ItemNode> 
  <el-form-item 
    v-else
    :label="label" 
    :style="{'display': recordVisible ? '' : 'none'}"
    :rules="recordRules"
    :prop="recordProps"
    :key="record.key"
    :required="recordRequired" 
    :id="record.model" 
    :name="record.model"
    :label-width="labelWidth"
    >       
    <ItemNode 
      :record="record"
      :disabled="disabled" 
      :preview="preview"
      :isDragPanel="isDragPanel"
      :selectItem="selectItem" 
      :prop-prepend="propPrepend"
      :models="models" 
      @handleSelectItem="handleSelectItem"
      >
        <!-- 递归传递插槽!!! -->
        <template v-for="slot in Object.keys($slots)"  :slot="slot">
          <slot :name="slot" :record="record"/>
        </template>
      </ItemNode> 
  </el-form-item>  
</template>

import ItemNode from './node.vue'

 

  1.v-if="isLayout":是否为预览模式

 

//packages/form-design/items/node.vue

<template>

  <component
        :record="record"
        :style="{
          margin: record.margin && record.margin.length > 0 ? record.margin.join('px ') + 'px' : '0px',
          borderRadius: (record.itemBorderRadius ? record.itemBorderRadius : 0) + 'px',
          backgroundColor: record.backgroundColor ? record.backgroundColor  : '',

        }"
        :disabled="disabled"
        :preview="preview"
        :isDragPanel="isDragPanel"
        :selectItem="selectItem"
        :prop-prepend="propPrepend"
        :models.sync="models"
        @handleSelectItem="handleSelectItem"
        @handleFocus="handleFocus"
        @handleBlur="handleBlur"
        :is="customComponent">
      <!-- 递归传递插槽!!! -->
      <template v-for="slot in Object.keys($slots)"  :slot="slot">
        <slot :name="slot" :record="record"/>
      </template>  
  </component>
</template>

 

ok终于到了最后一层

最终的关键就是这么行代码

  • :is="customComponent":动态绑定组件名称,根据 customComponent 的值来渲染不同的组件。
customComponent() {

      // 判断是否自定义组件
      if(this.customComponents && this.customComponents.length > 0) {
        const cs = this.customComponents.filter(t=> t.type == this.record.type)

        if(cs && cs.length > 0) {
          return cs[0].component
        }
      }

      const selectItemType = this.record.type
            // 将数组映射成json
      if(this.items && this.items.length > 0) {
            for(let i = 0 ; i < this.items.length ; i++) {
              const itemList = this.items[i]

              if(itemList.list && itemList.list.length > 0) {
                const fs = itemList.list.filter(t=>t.type == selectItemType)
                if(fs && fs.length > 0) {
                  return fs[0].component
                }
              }

            }
      }
      return null
    },

 

 

2.数据格式

在这个项目上随便做的一个表格并导出数据

 

{
    "list": [
        {
            "type": "input",
            "options": {
                "defaultValue": "",
                "type": "text",
                "prepend": "",
                "append": "",
                "placeholder": "请输入",
                "maxLength": 0,
                "clearable": false,
                "hidden": false,
                "disabled": false
            },
            "label": "输入框",
            "labelWidth": -1,
            "width": "100%",
            "span": 24,
            "model": "input_17156872001522",
            "key": "input_17156872001522",
            "rules": [
                {
                    "required": false,
                    "message": "必填项",
                    "trigger": [
                        "blur"
                    ]
                }
            ],
            "dynamicLabel": false
        },
        {
            "type": "radio",
            "options": {
                "defaultValue": "",
                "placeholder": "请输入",
                "dynamic": 0,
                "options": [
                    {
                        "value": "1",
                        "label": "选项1"
                    },
                    {
                        "value": "2",
                        "label": "选项2"
                    }
                ],
                "methodType": "get",
                "dynamicPostData": "",
                "remoteFunc": "",
                "dataPath": "",
                "remoteValue": "",
                "remoteLabel": "",
                "dictType": "",
                "disableItemScript": "",
                "hidden": false,
                "disabled": false,
                "linkage": false,
                "linkData": []
            },
            "label": "单选框",
            "labelWidth": -1,
            "width": "100%",
            "span": 24,
            "model": "radio_17156872321432",
            "key": "radio_17156872321432",
            "rules": [
                {
                    "required": false,
                    "message": "必填项",
                    "trigger": [
                        "blur"
                    ]
                }
            ],
            "dynamicLabel": false
        },
        {
            "type": "button",
            "event_": false,
            "listen_": false,
            "options": {
                "size": "mini",
                "type": "primary",
                "align": "left",
                "control": "",
                "eventName": "",
                "script": "",
                "plain": false,
                "circle": false,
                "round": false,
                "disabled": false
            },
            "label": "按钮",
            "labelWidth": 0,
            "width": "100%",
            "span": 24,
            "model": "button_17156901763582",
            "key": "button_17156901763582",
            "dynamicLabel": false
        },
        {
            "type": "rate",
            "options": {
                "max": 5,
                "defaultValue": 0,
                "allowHalf": false,
                "hidden": false,
                "disabled": false
            },
            "label": "评分",
            "labelWidth": -1,
            "width": "100%",
            "span": 24,
            "model": "rate_17156901773022",
            "key": "rate_17156901773022",
            "rules": [
                {
                    "required": false,
                    "message": "必填项",
                    "trigger": [
                        "blur"
                    ]
                }
            ],
            "dynamicLabel": false
        }
    ],
    "config": {
        "labelPosition": "top",
        "labelWidth": 80,
        "size": "mini",
        "outputHidden": true,
        "hideRequiredMark": false,
        "syncLabelRequired": false,
        "labelSuffix": "",
        "customStyle": ""
    }
}
  1. type:表示该组件的类型,该对象的类型为 "rate",用于评分。
  2. options:表示该组件的选项,包括:
  3. label:表示该组件的标签文本,值为 "评分"。
  4. labelWidth:表示该组件的标签宽度,值为 -1,表示使用系统默认值。
  5. width:表示该组件的宽度,值为 "100%"。
  6. span:表示该组件所占的栅格数,值为 24。
  7. model:表示该组件的 v-model 绑定值的变量名,值为 "rate\_17156901773022"。
  8. key:表示该组件的唯一标识,值为 "rate\_17156901773022"。
  9. rules:表示该组件的校验规则,包括:
  10. dynamicLabel:表示该组件的标签是否动态显示,值为 false。

 

 3.总结

在翻了许许多多的低开项目后,发现,

巨大多数的低开项目要么引擎核心闭源,要么物料组件库闭源

而这个项目,所有的东西都开源了,真真正正的开源,真的牛bi

非常值得自学的一个低开项目

 

标签:vue,false,form,labelWidth,items,组件,Star,解析,type
From: https://www.cnblogs.com/FatTiger4399/p/18192155

相关文章

  • LSTM卷土重来!xLSTM:一举超越Mamba、Transformer!
    前言 LSTM:这次重生,我要夺回Transformer拿走的一切。本文转载自新智元仅用于学术分享,若侵权请联系删除欢迎关注公众号CV技术指南,专注于计算机视觉的技术总结、最新技术跟踪、经典论文解读、CV招聘信息。CV方向的准研究生们,未来三年如何度过?招聘高光谱图像、语义分割、diffu......
  • ClickHouse vs StarRocks 全场景MPP数据库选型对比
    ClickHousevsStarRocks选型对比面向列存的DBMS新的选择Hadoop从诞生已经十三年了,Hadoop的供应商争先恐后的为Hadoop贡献各种开源插件,发明各种的解决方案技术栈,一方面确实帮助很多用户解决了问题,但另一方面因为繁杂的技术栈与高昂的维护成本,Hadoop也渐渐地失去了原本......
  • JUC 源码解析:lock锁与synchronized锁的区别
    JUC源码解析:lock锁与synchronized锁的区别本文使用jdk1.8Lock锁的使用注意事项要在finally块中释放锁。保障锁一定能被释放不要把加锁代码写进try块里。因为我们可能会自己实现Lock接口,在一些实现中,如果获取锁时发生了异常,可能导致锁被无故释放lock与synchroniz......
  • C# WinForm 解除资源文件的占用并删除
    1.删除未解除占用的资源时2.调用WindowsAPI函数解除文件占用[DllImport("kernel32.dll",SetLastError=true)][return:MarshalAs(UnmanagedType.Bool)]staticexternboolCloseHandle(IntPtrhObject);[DllImport("kernel32.dll"......
  • 绝对定位(absolute)居中问题:transform: translate(-50%);
     transform:translate(-50%); translate(50%)相当于translateX(50%),表示沿X轴方向平移元素自身宽度的50%。 绝对定位是最常见的问题是难以居中,所以可以改变元素的中心,来达到居中的效果position:absolute;left:50%;transform:translate(-50%); exposit......
  • Formality Template
    set_host_options-max_cores8set_app_varhdlin_interface_only""set_app_varverification_failing_point_limit3000set_app_varsh_continue_on_errortrueset_app_varsh_new_variable_messagefalseset_app_varsynopsys_auto_setuptrueset_app_varhdlin......
  • js车牌识别接口开发示例、Vin解析接口
    采用手机app扫描车牌来管理停车场车位或其他场景车位的方式已成为主流,车辆管理员们不再像以前一样使用一个小本子和笔来记录下车牌号码。如此一来,工作也仿佛变得轻松了不少,下面就让翔云为您介绍如何应用OCR技术来实现车牌识别功能。首先,我们来看一下车牌识别的功能一般都......
  • 机器学习策略篇:详解为什么是人的表现?(Why human-level performance?)
    为什么是人的表现?在过去的几年里,更多的机器学习团队一直在讨论如何比较机器学习系统和人类的表现,为什么呢?认为有两个主要原因,首先是因为深度学习系统的进步,机器学习算法突然变得更好了。在许多机器学习的应用领域已经开始见到算法已经可以威胁到人类的表现了。其次,事实证明,当试......
  • PXE+Kickstart无人值守安装安装Centos7.9
    目录一、什么是PXE1、简介2、工作模式3、工作流程二、什么是Kickstart1、简介2、触发方式三、无人值守安装系统工作流程四、实验部署1、环境准备2、服务端:关闭防火墙和selinux3、添加一张仅主机的网卡4、配置仅主机的网卡4.1、修改网络连接名4.2、配IP地址4.3、重启网卡5、配置DHC......
  • 万事通,专精部分领域的多功能 Transformer 智能体
    介绍我们很高兴分享“万事通”(JackofAllTrades,简称JAT)项目,该项目旨在朝着通用智能体的方向发展。该项目最初是作为对Gato(Reed等,2022年)工作的公开复现启动的,Gato提出训练一种能够执行视觉与语言以及决策任务的Transformer。于是我们首先构建了Gato数据集的开放......