好家伙,

在写项目的时候,我发现自己的平台的组件写的实在是太难看了,于是想去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

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

Gitee千Star优质项目解析: ng-form-element低开引擎解析的更多相关文章

  1. AngularJS进阶(三十九)基于项目实战解析ng启动加载过程

    基于项目实战解析ng启动加载过程 前言 在AngularJS项目开发过程中,自己将遇到的问题进行了整理.回过头来总结一下angular的启动过程. 下面以实际项目为例进行简要讲解. 1.载入ng库 2 ...

  2. 保姆级教程,如何发现 GitHub 上的优质项目?

    先看再点赞,给自己一点思考的时间,微信搜索[沉默王二]关注这个靠才华苟且的程序员.本文 GitHub github.com/itwanger 已收录,里面还有一线大厂整理的面试题,以及我的系列文章. ...

  3. 学习SpringBoot,整合全网各种优秀资源,SpringBoot基础,中间件,优质项目,博客资源等,仅供个人学习SpringBoot使用

    学习SpringBoot,整合全网各种优秀资源,SpringBoot基础,中间件,优质项目,博客资源等,仅供个人学习SpringBoot使用 一.SpringBoot系列教程 二.SpringBoot ...

  4. 1K star+ 的项目是如何炼成的?

    前言 首先标题党一下,其实这篇文章主要是记录我的第二个过 1K star 的项目 Java-Interview,顺便分享下其中的过程及经验. 需求选择 Java-Interview 之所以要做这个项目 ...

  5. mybatis源码-解析配置文件(二)之解析的流程

    目录 1. 简介 2. 配置文件解析流程分析 2.1 调用 2.2 解析的目的 2.3 XML 解析流程 2.3.1 build(parser) 2.3.2 new XMLConfigBuilder( ...

  6. Fixflow引擎解析(三)(模型) - 创建EMF模型来读写XML文件

    Fixflow引擎解析(四)(模型) - 通过EMF扩展BPMN2.0元素 Fixflow引擎解析(三)(模型) - 创建EMF模型来读写XML文件 Fixflow引擎解析(二)(模型) - BPMN ...

  7. Fixflow引擎解析(二)(模型) - BPMN2.0读写

    Fixflow引擎解析(四)(模型) - 通过EMF扩展BPMN2.0元素 Fixflow引擎解析(三)(模型) - 创建EMF模型来读写XML文件 Fixflow引擎解析(二)(模型) - BPMN ...

  8. Fixflow引擎解析(一)(介绍) - Fixflow开源流程引擎介绍

    Fixflow引擎解析(四)(模型) - 通过EMF扩展BPMN2.0元素 Fixflow引擎解析(三)(模型) - 创建EMF模型来读写XML文件 Fixflow引擎解析(二)(模型) - BPMN ...

  9. Android网络请求与数据解析,使用Gson和GsonFormat解析复杂Json数据

    版权声明:未经博主允许不得转载 一:简介 [达叔有道]软件技术人员,时代作者,从 Android 到全栈之路,我相信你也可以!阅读他的文章,会上瘾!You and me, we are family ...

  10. spring mvc: 多解析器映射(资源绑定视图解析器 + 内部资源[普通模式/]视图解析器)

    spring mvc: 多解析器映射(资源绑定视图解析器 + 内部资源[普通模式/]视图解析器) 资源绑定视图解析器 + 内部资源(普通模式)视图解析器 并存方式 内部资源视图解析器: http:// ...

随机推荐

  1. #贪心#洛谷 6927 [ICPC2016 WF]Swap Space

    题目 分析 可以发现能将硬盘容量变大的优先,这种硬盘就是以格式化前的大小升序排序. 然后如果硬盘容量变小,那就是先填格式化后较大的硬盘(因为装完可以提供较大的空间) 代码 #include <c ...

  2. OpenHarmony社区运营报告(2023年6月)

      本月快讯 • 6月12日,以"OpenHarmony共建开放,共享未来"为主题的2023开放原子全球开源峰会OpenAtom OpenHarmony(以下简称"Ope ...

  3. WPF/MVVM模式入门教程(二):实现INotifyPropertyChanged接口

    引用:https://www.cnblogs.com/flh1/p/12447188.html 1.创建NotifyPropertyChanged类 我们在common文件夹下创建一个名为Notify ...

  4. IE8发送ajax请求无效

    IE是个非常有个性的浏览器,常规的东西在他这个都不太好使. 最开始发送ajax请求,总是不成功,也没啥报错,反正就是请求被忽略了 然后我就考虑用原生的JS来实现,然后就:哎呀  可以了...... x ...

  5. MogDB/openGauss如何实现事务的rollback

    MogDB/openGauss 如何实现事务的 rollback 本文出处:https://www.modb.pro/db/113262 数据库最主要的功能就是存储数据,然而我们在进行数据库操作时,却 ...

  6. 如何巧妙应对iOS键盘难题?

    前言 写过移动端的同学或多或少都遇到过软键盘带来的各种各样的问题,最典型的就是输入框被软键盘遮挡.fixed元素失效等问题,并且这些问题在iOS上的表现让人难以接受. webview的差异 在移动端上 ...

  7. 开发指导—利用组件&插值器动画实现HarmonyOS动效

    一. 组件动画 在组件上创建和运行动画的快捷方式.具体用法请参考通用方法. 获取动画对象 通过调用animate方法获得animation对象,animation对象支持动画属性.动画方法和动画事件. ...

  8. http协议重新整理——————历史[一]

    前言 简单整理一些http协议. 正文 20 世纪 60 年代,美国国防部高等研究计划署(ARPA)建立了 ARPA 网,它有四个分布在各地的节点,被认为是如今互联网的"始祖". ...

  9. 重新点亮shell————什么是shell[一]

    前言 这里简介一下什么是shell. 写linux和shell 系列是为了后面的docker 系列的整理,本来想直接整理k8s的,但是呢,想想docker 系列整理完了的话,那么整理k8s系列就没有那 ...

  10. singalr 可以连接但是无法发送消息

    前言 在一次测试singalr的过程中,发现一个问题,那就是连接成功了,但是发送消息没有响应. 原因及解决 如何可以连接但是发不了消息,net的锅,需要4.0以上,所以我们发布iis的时候也应该选择4 ...