el-form-renderer 使用指南

news2024/11/26 2:37:06

目录

前言

起步 

使用

update-form && getFormValue

表单项动态显示或隐藏(hidden)

表单数据联动(on)

输入/输出格式化(inputFormat/outputFormat)

set-options

el-form-renderer 实践案例

案例一

案例二

自定义组件接入指南


前言

el-form-renderer是基于element的表单渲染器,动态渲染,数据驱动

el-form-renderer/README-zh.md at dev · FEMessage/el-form-renderer · GitHub

el-form-renderer是基于 element-ui 封装的表单渲染器,但不局限于 element-ui 组件。在完整继承了 element 的form表单属性的基础上进行了简单扩展,一些非表单组件或者封装的自定义组件,如图片上传、富文本等也可进行整合,从而用户能够通过使用一段预设的数据渲染出一个完整的表单。

起步 

​# Step1 确认你已经正确安装并使用了 element-ui
yarn add @femessage/el-form-renderer
<template>
  <el-form-renderer :content="content"></el-form-renderer>
</template>

<script>
  import ElFormRenderer from '@femessage/el-form-renderer'

  export default {
    components: {
      ElFormRenderer,
    },
    data() {
      return {
        content: [],
      }
    },
  }
</script>

使用

支持 el-form 上的所有属性。

  • content:[ObjectArray] 定义表单的内容,每一个 Object 代表一个原子表单 el-input, el-select, ...,一切 el-form-item 上的属性都在此声明,而对于 el-input 等之上的属性在 $el 属性上进行声明,该 Object 上还存在其他属性,例如: id, type,label, options可选的,等。还有hidden定义其是否隐藏等属性
  • id: id: string  每一个原子都存在 id,用于存储该原子的值,不能重复
  • type: string  可以是element提供的所有表单组件类型,如传入'input',则渲染出'el-input,当type="group"时使用 items内依然遵循同一层级的id不重复的原则
  • readonly 只读的   当 type === 'input' 时展示文本值, 当 type === 'select' 时展示对应。 label 对于其他组件等同于 disabled = true
  • default: 默认值
  • options ({label: string; value?: any}[])具有选择功能的原子表单可用此定义可选项 select, radio-group, radio-button, checkbox-group, checkbox-button
  • hidden 传入一个方法,并返回 boolean,返回 true 时则隐藏该表单项 * formValue 为当前 form 值,item 为当前表单项的定义
  • el  用于定义具体原子表单(如el-input)的属性,比如定义el-input的placeholder
  • component   component适用于渲染局部注册组件和自定义组件,而type适用于带el-前缀的全局组件
  • label 设置el表单项的标签

update-form && getFormValue

  • update-form 更新表单方法  默认情况下,updateForm 来者不拒,不在表单设置内的值,也可以存储进去
  • getFormValue 默认情况下,通过 updateForm 设置的所有值都会输出。 如果只想输出根据 content 设置的表单项的值,可传入 {strict: true}
<template>
  <div class="update-form">
    <el-form-renderer :content="content" inline ref="formRender">
      <el-button @click="setValue">更新表单</el-button>
      <div>
        <el-button type="primary" @click="getValue(false)">获取数据</el-button>
        <el-button type="primary" @click="getValue(true)"
          >获取数据过滤掉字段</el-button
        >
      </div>
    </el-form-renderer>
    <pre>{{ value }}</pre>
  </div>
</template>

<script>
export default {
  name: "update-form",
  data() {
    return {
      value: {},
      content: [
        {
          id: "name",
          type: "input",
          label: "name",
          el: {
            placeholder: "name",
          },
        },
        {
          id: "area",
          type: "select",
          label: "area",
          el: {
            placeholder: "area",
          },
          options: [
            {
              label: "shanghai",
              value: "shanghai",
            },
            {
              label: "beijing",
              value: "beijing",
            },
          ],
        },
      ],
    };
  },
  methods: {
    getValue(strict) {
      const value = this.$refs.formRender.getFormValue({ strict });
      this.value = value;
    },
    setValue() {
      this.$refs.formRender.updateForm({
        name: "alvin",
        area: "shanghai",
        // 设置冗余字段
        extraKey: "extraValue",
      });
    },
  },
};
</script>

表单项动态显示或隐藏(hidden)

以通过 hidden 控制某一表单项的显示或隐藏。

<template>
  <div>
    <el-form-renderer :content="content"></el-form-renderer>
  </div>
</template>

<script>
import ElFormRenderer from "@femessage/el-form-renderer";

export default {
  components: {
    ElFormRenderer,
  },
  data() {
    return {
      content: [
        {
          type: "select",
          id: "selected",
          label: "选择项目",
          options: [
            {
              label: "项目A",
              value: "optionA",
            },
            {
              label: "项目B",
              value: "optionB",
            },
          ],
        },

        {
          label: "资料",
          type: "input",
          id: "data",
          el: {
            placeholder: "项目B的具体内容",
          },
          hidden: (form, item) => {
            return this.hiddenChange(form, item);
          },
        },
      ],
    };
  },
  methods: {
    hiddenChange(form, item) {
      console.log(form); //form 收集的数据
      console.log(item); //触发元素
      return form.selected !== "optionB";
    },
  },
};
</script>

表单数据联动(on)

可以通过 on 来监听 blur , focus 等事件来实现表单联动 监听表单项发出的事件
<template>
  <div>
    <el-form-renderer :content="content"></el-form-renderer>
  </div>
</template>

<script>
import ElFormRenderer from "@femessage/el-form-renderer";

export default {
  components: {
    ElFormRenderer,
  },
  data() {
    return {
      content: [
        {
          label: "英文名",
          type: "input",
          id: "fullName",
          on: {
            blur: ([event], updateForm) => {
              const value = event.target.value;
              const lastName = value.split(" ")[1]; // 通过空格分割出内容
              updateForm({ lastName }); // 更新其他表单项
            },
          },
        },
        {
          label: "姓氏",
          type: "input",
          id: "lastName",
        },
      ],
    };
  },
};
</script>

输入/输出格式化(inputFormat/outputFormat)

拿 日期范围选择器 为例,组件输出的值是一条字符串,但后端接口格式是两个字段 {startDate, endDate},则此时需要对数据进行格式化处理

inputFormat 转换输入的数据, 使其变成表单项需要的数据格式

<template>
  <el-form-renderer :content="content" ref="form" />
</template>

<script>
export default {
  data() {
    return {
      content: [
        {
          el: {
            type: 'daterange',
            placeholder: '选择日期',
            valueFormat: 'yyyy-MM-dd'
          },
          type: 'date-picker',
          id: 'date',
          label: '日期',
          // 接口设计的时间范围是两个字段 '2019-07-23','2019-07-24'
          // 处理后的值为 [ '2019-07-23', '2019-07-24' ]
          inputFormat: row => ([row.startDate, row.endDate])
        }
      ]
    }
  }
}
</script>

outputFormat 转换输出的数据, 使其变成需要的(接口期望的)数据格式

<script>
export default {
  data() {
    return {
      content: [
        {
          el: {
            type: 'daterange',
            placeholder: '选择日期',
            valueFormat: 'yyyy-MM-dd'
          },
          type: 'date-picker',
          id: 'date',
          label: '日期', 
          // 处理前的值为 date: [ '2019-07-23', '2019-07-24' ]
          // 处理后的值为 {startDate: '2019-07-23', endDate: '2019-07-24'}
          outputFormat: val => {
            if (!val) {
              return {startDate: '', endDate: ''}
            }
            return {
              startDate: val[0],
              endDate: val[1]
            }
          }
        }
      ]
    }
  }
}
</script>

set-options

使用setOptions更新选择选项

<template>
  <el-form-renderer ref="form" :content="content" inline>
    <el-button @click="setOptions">更新options</el-button>
  </el-form-renderer>
</template>
<script>
export default {
  name: "select-demo",
  data() {
    return {
      content: [
        {
          id: "area",
          type: "select",
          label: "select",
          el: {
            placeholder: "select",
          },
          options: [
            {
              label: "shanghai",
              value: "shanghai",
            },
            {
              label: "beijing",
              value: "beijing",
            },
          ],
        },
      ],
    };
  },
  methods: {
    setOptions() {
      this.$refs.form.setOptions("area", [
        {
          label: "guangzhou",
          value: "guangzhou",
        },
        {
          label: "hangzhou",
          value: "hangzhou",
        },
      ]);
    },
  },
};
</script>

el-form-renderer 实践案例

案例一

A 系统有一个解析简历的功能,后端接口只能解析电话、邮箱,也即接口只返回 phone、email 两个字段。后来接口更新了,支持解析姓名:

后端:简历解析接口更新了,现在会返回多一个字段 name,你前端那边也更新一下吧。 前端:您随便加,接口直接更新就行了,前端不用改。 后端:这么神奇的吗?这是怎么做到的?

 那么前端是如何做到接口返回多一个字段,自己却不用修改代码的呢?

分析

原因在于使用了 el-form-renderer 使用了 updateForm 来更新表单值。 updateForm 方法接受一个对象,只要传入对象的 key 与表单的 id 对应上即可更新数据。代码片段如下:

<template>
  <el-form-renderer :content="content" ref="form" />
</template>

<script>
export default {
  data() {
    return {
      content: [
        {
          type: 'input',
          id: 'name',
          label: '名称'
        },
        {
          type: 'input',
          id: 'phone',
          label: '电话'
        },
        {
          type: 'input',
          id: 'email',
          label: '邮箱'
        },
        // ...
      ],
    }
  },
  methods: {
    async fetch() {
      const data = await fetchData()  // data: Object
      // data 中返回多了一个字段 name,也不需要修改代码
      this.$refs.form.updateForm(data)
    }
  }
}
</script>

所以,即使后端丰富了这个 data ,前端也可以“照吃不误”

如果直接使用 el-form 则无法完成这种操作:你需要手动去更新每个与 el-form-item 绑定的 data 值

<template>
  <el-form ref="form" :model="form">
    <el-form-item label="名称">
        <el-input v-model="form.name"></el-input>
    </el-form-item>
  </el-form>
</template>

<script>
export default {
  data() {
    return {
      form: {
        // 每一个表单项需要主动绑定
        name: '',
        phone: '',
        email: '',
      },
    }
  },
  methods: {
    async fetch() {
      const {name} = await fetchData()  // data: Object
      this.form.phone = data.phone
      this.form.email = data.email
      // data 中返回多了一个字段 name,需要多写下面一行代码
      this.form.name = name
    }
  }
}
</script>

案例二

场景

B 系统的表单页面比较多,其中不乏带有复杂组件的表单,如下图红框片所示:

 

直接使用 el-form 开撸,整个页面耦合在一起代码超过 1000 行。

使用 el-form-renderer 后,通过拆分组件,整个页面代码量在 300 行左右,业务组件代码量在 100~300 行之间。

明显能感觉到页面简洁了许多,维护性大大提高。

那么,el-rorm-renderer 是怎么做到精简主页面代码的呢?

分析

秘诀在于 el-form-renderer 支持通过 component 属性渲染自定义组件、在组件内部定义检验规则,提高了拆分页面的可能性。

下面代码示例中,把选择优惠券的表格,抽离成了一个单独的组件。

<!--表单主页面-->
<template>
  <el-form-renderer :content="content" ref="form" />
</template>
<script>
import SelectTableList from './select-table-list.vue'
export default {
  data() {
    return {
      content: [
        // ...
        {
          id: 'selectedCoupon',
          // 渲染自定义 table 组件
          component: SelectTableList,  
          label: '选择优惠券'
        },
        // ...
      ],
    }
  }
}
</script>

下面是自定义 table 组件示例代码。

<!--自定义 table 组件示例代码-->
<template>
  <div class="select-table-list">
    <el-button type="primary" size="small" @click="visible = true">选择</el-button>
    <el-table :data="selectedList" border></el-table>
    <!--
            省略一些代码
    -->
  </div>
</template>
<script>
export default {
  name: 'select-table-list',
  // 自定义校验规则
  rules: [
    {
      required: true,
      message: '自定义组件的提醒消息'
    }
  ],
  props: ['value'],
  data() {
    return {
      visible: false,
      selectedList: []
    }
  },
  methods: {
    confirm() {
      const selectedVal = 'table选中的值'
      // 更新 value 值,这样 el-form-renderer 可以通过 getFormValue() 拿到该值
      this.$emit('input', selectedVal)
      this.visible = false
    }
  }
}
</script>

自定义组件接入指南

el-form-renderer 的 type 有限, 默认只能渲染普通的表单项, 假如现在要渲染一个上传组件, type 就不够用了, 那怎么办呢? 这时候 component 选项就派上用场了

本文将介绍如何开发符合 el-form-renderer 接入标准的自定义组件, 实现对自定义组件的渲染

自定义组件接入的关键是在组件内部实现 v-model

建议在自定义组件上绑定 $attrs 和 $listeners

el-form-renderer 对 v-model 的要求是:

  • 有一个 props 为 value
  • 对外触发 input 事件
<template>
  <el-form-renderer :content="content" />
</template>

<script>
import MyInput from "@/components/my-input.vue";
export default {
  data() {
    return {
      content: [
        {
          component: MyInput,
          id: "myInput",
          label: "label",
          // 传入组件属性
          el: {
            placeholder: "请输入一个 title",
            // type: "submit", // submit button
            title: "这是一个标题", // custom defined props
          },
          // 传入组件事件
          on: {
            focus: ([event], updateForm) => {
              console.log(event.target.value); // output: input value
            },
            customEvent: ([value, msg], updateForm) => {
              console.log(msg); // output: 'message'
            },
          },
        },
        {
          id: "document",
          type: "input",
          el: {
            type: "textarea",
          },
        },
      ],
    };
  },
};
</script>
<template>
  <div>
    <!-- 自定义组件 my-input -->
    <el-input
      :value="value"
      @input="onInput"
      v-bind="$attrs"
      v-on="$listeners"
    />
  </div>
</template>
<script>
export default {
  props: {
    value: String,
    title: String,
  },
  watch: {
    value(value) {
      this.$emit("customEvent", value, "message");
    },
  },
  methods: {
    onInput(val) {
      this.$emit("input", "my-input: " + val);
    },
  },
};
</script>

需要注意,on 中的 function 定义,组件 emit 事件的 payload 将以「数组」的方式,回调到第一个参数

第二个参数为 updateForm 方法

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/480278.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Starting Windows PowerShell (启动 Windows PowerShell)

Starting Windows PowerShell (启动 Windows PowerShell) Windows PowerShell is a scripting engine .DLL that’s embedded into multiple hosts. The most common hosts you’ll start are the interactive command-line powershell.exe and the Interactive Scripting Envi…

【Java笔试强训 26】

&#x1f389;&#x1f389;&#x1f389;点进来你就是我的人了博主主页&#xff1a;&#x1f648;&#x1f648;&#x1f648;戳一戳,欢迎大佬指点! 欢迎志同道合的朋友一起加油喔&#x1f93a;&#x1f93a;&#x1f93a; 目录 一、选择题 二、编程题 &#x1f525;跳台阶扩…

Redis`数据结构`与`对象`概述

文章目录 Redis数据结构与对象概述一、数据结构1、简单动态字符串&#xff08;SDS&#xff09;SDS结构体定义SDS结构示意图使用SDS的五个优点 2、双端链表&#xff08;list&#xff09;链表结构体定义list结构示意图 3、字典&#xff08;dict&#xff09;字典结构体定义dict结构…

想要成为 NLP 领域的大牛?从 ChatGPT 的 5 大自然语言模型开始了解吧(LM、Transformer、GPT、RLHF、LLM)——小白也能看得懂

目录 前言ChatGPT基础科普——知其一点所以然1. LM2. Transformer3. GPT4. RLHF5. LLM 参考资料其它资料下载 前言 如果想在自然语言处理&#xff08;Natural Language Processing&#xff0c;NLP&#xff09;领域内脱颖而出&#xff0c;那么你一定不能错过 ChatGPT 的 5 大自然…

软件设计师笔记

软件设计师笔记 计算机组成与体系结构 数据的表示、计算机结构、Flynn分类法、CISC与RISC、流水线技术、存储系统、总线系统、可靠性、校验码 1. 数据的表示 &#xff08;一&#xff09;进制转换 R进制转十进制使用按权展开法&#xff1a; 十进制转R进制使用短除法 二进制…

Python——狂肝两万字带你学会【类与对象】

目录 01-初始对象 生活中的数据组织 程序中的数据组织​ 使用对象组织数据 总结01 02-类的成员方法 类的定义和使用 成员变量和成员方法 成员方法的定义语法 注意事项 成员方法——代码演示 总结02 03-类和对象 现实世界的事物和类 类和对象 使用类和对象描述…

Java 基础进阶篇(三)—— 权限修饰符、final 关键字与枚举

文章目录 一、权限修饰符二、final 关键字2.1 final 作用2.2 final 修饰变量举例2.3 常量 三、枚举3.1 枚举的格式3.2 枚举的特征3.3 枚举的应用 一、权限修饰符 权限修饰符 用于约束成员变量、构造器、方法等的访问范围。 权限修饰符&#xff1a; 有四种作用范围由小到大 (p…

vue+element 多选级联选择器自定义props

前言 我这里分享的是Cascader 级联选择器中的多选、以及如何自定义props的使用详解 1.使用Cascader 级联选择器 效果 代码 <div class"block"><span class"demonstration">默认显示所有Tag</span><el-cascader:options"op…

Vue电商项目--vuex模块开发

vuex状态管理库 vuex是什么&#xff1f; vuex是官方提供的一个插件&#xff0c;状态管理库&#xff0c;集中式管理项目中组件共有的数据。 切记&#xff0c;并不是全部的项目都需要Vuex,如果项目很小&#xff0c;完全不需要vuex,如果项目很大&#xff0c;组件很多&#xff0…

一道Python初学者常犯错误解析

1. 引言 在Python学习中&#xff0c;经常会遇到各种各样的代码错误&#xff0c;尤其对于初学者而言&#xff0c;明明觉得逻辑上是对的&#xff0c;但是代码运行起来&#xff0c;往往不是自己想要的结果。 本文就最近在某平台看到的一个常见错误进行展开&#xff0c;帮助大家更…

06 虚拟化Open vSwitch环境部署

文章目录 06 虚拟化Open vSwitch环境部署6.1 安装Open vSwitch网桥6.1.1 安装Open vSwitch组件6.1.1.1 安装Open vSwitch组件6.1.1.2 启动Open vSwitch服务6.1.1.3 设置Open vSwitch服务随系统自动启动 6.1.2 确认安装是否成功6.1.2.1确认 Open vSwitch组件是否安装成功6.1.2.2…

kill 信号

kill -0 PidNum 参数是0&#xff0c;不会发送任何的信号&#xff0c;不会关闭程序&#xff0c;但会执行错误检查&#xff0c;对程序运行状态进行监控。可以用他来检测某个进程ID或进程组ID是否存在。从理解上看&#xff0c;作用相当于ps -p 。 进程已停止、不存在或其他异…

前端小白是如何利用chatgt用一周时间从做一款微信小程序的

前端小白是如何利用chatgt用一周时间从0做一款微信小程序的 随着chatgpt的大火&#xff0c;真的是在工作上给各行各业的人带来了极大的便利&#xff0c;本人是一个java程序员&#xff0c;其实我自己是一直想开发一款属于自己的小程序的&#xff0c;但是迫于对前端知识的贫瘠&a…

【五一创作】VimPlug插件配置

目录 Install Question Q1&#xff1a;字体乱码 Q2&#xff1a;插件配置 Q3&#xff1a;安装扩展插件 Q4&#xff1a;查看安装插件状态 Q5&#xff1a;查看默认插件 Q6&#xff1a;卸载插件 Q7&#xff1a;增加用户配置 Install Github地址&#xff1a;GitHub - chxu…

内网渗透之横向移动NTMLRelay(中继)攻击-InveighNTLM-Relay重放

横向移动 NTLM中继攻击 Relay重放(smb) 适用于无法获取hash或密码时使用 NTML Relay重放包括smb to relay ldap ews webserver: 执行下面的命令时会默认以当前用户名和密码去登录目标计算机 dir \\ 192.168.3.32\c$webserver切换到本地的administrator时 dir \\ 192.168.3.3…

权限提升:令牌窃取 || 进程注入.

权限提升&#xff1a;令牌窃取 || 进程注入. 权限提升简称提权&#xff0c;由于操作系统都是多用户操作系统&#xff0c;用户之间都有权限控制&#xff0c;比如通过 Web 漏洞拿到的是 Web 进程的权限&#xff0c;往往 Web 服务都是以一个权限很低的账号启动的&#xff0c;因…

管理系统的实现_03

文章目录 登录界面的开发安装axios用于前后端交互第一步、在项目目录下执行命令第二步、在main.js文件夹添加如下代码第三步、使用this.axios 即可访问到 Login.vue 完整代码如下搭建第一个springboot项目第一步、修改配置文件(application.properties)第二步、创建包目录 用sp…

希尔排序(C++)

希尔排序 是插入排序的一种&#xff0c;也是缩小增量排序。希尔排序是记录按下标的一定增量分组&#xff0c;对每组使用直接插入排序算法排序&#xff1b;随着增量逐渐减少&#xff0c;每组包含的关键词越来越多&#xff0c;当增量减至1时&#xff0c;整个文件恰被分成一组&am…

常用的极限

常用的极限 方法1 利用基本极限求极限 1.常用的基本极限 一个函数极限是非零常数&#xff0c;分母极限为零&#xff0c;分子极限必为零 幂指函数转为指数函数的形式,再等价代换 方法二 分子分母凑成可以使用等价无穷小代换的形式 arcsinx 和 sin x 作为分子是相减的. 1 先使用…

数据结构之带头循环双向链表

目录 1.何为双链表&#xff1f; 2.带头循环双向链表 1.函数接口与结构体 2.初始化链表 3.销毁链表 4.打印链表 5.创建节点 6.尾插 7.尾删 8.头插 9.头删 10 查找节点 11.在pos前插入x 12.删除pos位置的值 在学习了单链表之后&#xff0c;我们发现单链表弥补了了顺…