好家伙,

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

    题目 给出一个\(n*m\)的矩阵,里面有""和"."两种符号,要求把最少的""变成".", 使得".&quo ...

  2. 新零售SaaS架构:客户管理系统架构设计(万字图文总结)

    什么是客户管理系统? 客户管理系统,也称为CRM(Customer Relationship Management),主要目标是建立.发展和维护好客户关系. CRM系统围绕客户全生命周期的管理,吸引和 ...

  3. Windows开发的瑞士军刀,NewSPYLite发布

    宗旨:延续了SpyLite的方便易用,同时也丰富了更多的功能,更适合开发者使用. 在SpyLite的基础功能上,开发了更多人性化并且好用的功能,增强的信息的可读性,以及软件总体的可用性. New Sp ...

  4. C# 介绍、应用领域、入门、语法、输出和注释详解

    什么是 C#? C#(发音为"C-Sharp")是一种由 Microsoft 创建的面向对象的编程语言,运行在 .NET Framework 上.源于 C 家族,与流行的语言如 C ...

  5. Redis之父萨尔瓦多·桑菲利波又名安蒂雷斯

    萨尔瓦多·桑菲利波又名安蒂雷斯 个人博客连接 嗨,我是萨尔瓦多·桑菲利波,也被称为安提雷斯, 一位居住在卡塔尼亚的意大利计算机程序员. 我于7年1977月2020日出生在坎波贝洛迪利卡塔. 2022 ...

  6. C#的AOP(最经典实现)

    (适用于.NET/.NET Core/.NET Framework) [目录]0.前言1.第一个AOP程序2.Aspect横切面编程3.一个横切面程序拦截多个主程序4.多个横切面程序拦截一个主程序5. ...

  7. 【译】Visual Studio 中的 GitHub Copilot:2023年回顾

    在快速发展的软件开发世界中,保持领先是至关重要的.在 Visual Studio 中引入AI,特别是 GitHub Copilot,已经彻底改变了开发人员的编码方式.通过将 Copilot 集成到 V ...

  8. nginx重新整理——————http请求的11个阶段中的find_config[十三]

    前言 简单介绍一下find_config 与 preaccess 阶段. 正文 find_config 很大一部分工作是进行location的匹配. 来一张图看下location指令和merge_sl ...

  9. Android Studio制作简单登录界面

    实现目标 应用线性布局设计登录界面,要求点击输入学号时弹出数字键盘界面,点击输入密码时弹出字母键盘,出现的文字.数字.尺寸等全部在values文件夹下相应.xml文件中设置好,使用时直接引用.当用户名 ...

  10. java知识点查漏补缺-- 2020513

    重载和重写 方法重载(overload): 必须是同一个类 方法名(也可以叫函数)一样 参数类型不一样或参数数量不一样 方法的重写(override)两同两小一大原则: 方法名相同,参数类型相同 子类 ...