vue构建动态表单的方法示例


Posted in Javascript onSeptember 22, 2018

概述

后台管理系统里面有非常多的表单需求,我们希望能够通过写一个json格式的数据,通过vue的循环动态地去渲染动态表单。并且能够在外部得到渲染出来的表单的数据,可以对表单进行重置操作。我结合element ui的控件的下拉框,输入框,时间选择控件和vue-treeselect,做了一个动态表单。

vue构建动态表单的方法示例

v-model的理解

先简单讲一下vue-model是怎么玩的。其实vue-model相当于给表单元素传递一个value,外部监听input事件。所以我们自己封装表单组件的时候也是可以传递一个value值,监听input事件获取输入的值。

<input type="text" v-model="something">
<!--等价于-->
<input type="text"
    v-bind:value="something"
    v-on:input="something = $event.target.value">

封装表单组件

组件最重要的开发思想就是设计好输入输出。这里就以下拉框组件为例吧。使用的是element ui的下拉框,进行一个简单封装。
输入:name:每个表单的数据标识,如区域编码输入框,父元素应该传递areaCode过来。

value: 表单选择/输入的值,从父元素获取后赋值给currentValue,通过监听父元素的值实现同步变
化。

options:下拉框要渲染的选项值,一般是个对象数组。

输出:onInputEvent,emit一个input事件,让父元素能够感知组件的数据变化。

也就是可以在组件使用的地方监听input事件

<template>
 <el-form-item :label="label">
  <el-select v-model="currentValue" @input="onInputEvent">
   <el-option
    v-for="item in options"
    :key="item.value"
    :label="item.label"
    :value="item.value">
   </el-option>
  </el-select>
 </el-form-item>
</template>

<script>
 import formMixins from '../../../mixins/form-model'
 export default {
  name: "SelectList",
  props: ['name', 'label', 'value','options'],
  mixins: [formMixins],
  data() {
   return {
    currentValue: this.value
   }
  },
  methods: {
   onInputEvent(value) {
    this.$emit('input', this.name, value);
   }
  },
  watch: {
   value(val) {
    this.currentValue= val;
   }
  }
 }
</script>

一点封装

由于每个表单组件都是监听父元素的value值变化,数据变化时都是触发onInputEvent并执行this.$emit('input'),所以我们可以把这部分内容抽取出来放在mixins里面。

form-model.js

export default {
 props: ['name', 'value'],

 data () {
  return {
   currentValue: this.value
  };
 },
 methods: {
  onInputEvent(value) {
   this.$emit('input', this.name, value);
  },
  reset() {
   this.currentValue = "";
  }
 },
 watch: {
  value (val) {
   this.currentValue = val;
  }
 }
};

然后我们的下拉框组件就可以少写一些共用的代码,直接用 mixins: [formMixins]

<template>
 <el-form-item :label="label">
  <el-select v-model="currentValue" @input="onInputEvent">
   <el-option
    v-for="item in options"
    :key="item.value"
    :label="item.label"
    :value="item.value">
   </el-option>
  </el-select>
 </el-form-item>
</template>

<script>
 import formMixins from '../../../mixins/form-model'
 export default {
  name: "SelectList",
  props: ['name', 'label', 'value', 'options'],
  mixins: [formMixins],
  data() {
   return {
    currentValue: this.value
   }
  }
 }
</script>

动态生成表单

这里主要是根据配置的数据,循环生成表单组件。默认提供提交和重置按钮,如果不需要可以通过slot传递其他操作按钮。这里的要点主要有:

监听表单组件的数据变化:

每个表单组件都有一个name标识它的业务含义,绑定的数据也是formData[field.name],@input事件传递updateForm,在updateForm里面更新this.formData[name],保证了this.formData里面的数据是和表单组件选择/填写的内容一致。

重置时改变表单组件的数据:

因为组件内部会监听父元素的value,所以这里只要清空this.formData的值,组件内部的数据也会跟着清空。

<template>
 <div>
  <el-form :inline="true" ref="form" :model="formData" class="demo-form-inline">
   <el-col :span="field.cols" v-for="(field, index) in config.fieldsConfig" v-bind:key="index">
    <component :key="index"
          :is="field.fieldType"
          :label="field.label"
          :value="formData[field.name]"
          :multiple="field.multiple"
          @input="updateForm"
          v-bind="field"
          :options="field.options"
          :ref="field.name"
    >
    </component>
   </el-col>
   <slot name="buttons">
    <el-button type="primary" @click="submit" size="small">{{onSubmitText}}</el-button>
    <el-button type="default" @click="reset" size="small">{{onResetText}}</el-button>
   </slot>
  </el-form>
 </div>
</template>
<script>
 import SelectList from './basicComponent/SelectList'
 import TextInput from './basicComponent/TextInput'
 import TimeSelector from './basicComponent/TimeSelector'
 import SelectTree from './basicComponent/SelectTree'
 import StaffSelectPopedit from './businessComponent/StaffSelectPopedit'
 export default {
  name: "FormGenerator",
  components: { SelectList, TextInput, TimeSelector, SelectTree, StaffSelectPopedit},
  props: ["config", "value"],
  data() {
   return {
    formData: this.value,
    onSubmitText: this.config.buttons.onSubmitText || '提交',
    onResetText: this.config.buttons.onResetText || '重置'
   }
  },
  methods: {
   updateForm(fieldName, value) {
    this.formData[fieldName] = value;
   },
   submit() {
    this.$emit("submit");
   },
   reset() {
    for(var name in this.formData) {
     if(typeof this.formData === "String") {
      this.formData[name] = "";
     } else {
      this.formData[name] = null;
     }
    }
   }
  }
 }
</script>

业务使用的地方

像下拉框的选择数据,这些应该是后台渲染的,所以我们暂时用setTimeout模拟一下。感觉这里this.config.fieldsConfig[4].options写的不太优雅,依赖于配置数据的顺序肯定不是啥好事情。求大神指点。

<template>
 <div>
  <form-generator :config="config"
           @submit="getFormData"
           v-model="formData"
  >
  </form-generator>
 </div>
</template>
<script>
 import FormGenerator from '../components/form/FormGenerator'
 export default {
  name: "FormGeneratorDemo",
  components: { FormGenerator },
  created () {
   this.queryOrderType();
   this.queryAreaTree();
  },
  data() {
   return {
    formData: {
     orderCode: "",
     orderType: "",
     beginTime: "",
     endTime: "",
     area: [],
     staff:""
    },
    config: {
     fieldsConfig: [
      {
       name: 'orderCode',
       label: '定单编码',
       fieldType: 'TextInput',
       cols: 8
      },
      {
       name: 'orderType',
       label: '定单类型',
       fieldType: 'SelectList',
       options: [],
       cols: 8
      },
      {
       name: 'beginTime',
       label: '开始时间',
       fieldType: 'TimeSelector',
       cols: 8
      },
      {
       name: 'endTime',
       label: '结束时间',
       fieldType: 'TimeSelector',
       cols: 8
      },
      {
       name: 'area',
       label: '区域',
       fieldType: 'selectTree',
       options: [],
       multiple: true,
       cols: 8
      },
      {
       name: 'staff',
       label: '人员选择',
       fieldType: 'StaffSelectPopedit',
       cols: 8
      }
     ],
     buttons: {
      onSubmitText: '提交',
      onResetText: '重置'
     }
    }
   }
  },
  methods: {
   getFormData() {
    console.log(this.formData);
   },
   queryOrderType() {
    setTimeout(() => {
     this.config.fieldsConfig[1].options = [
      { label: 'select1', value: 'key1'},
      { label: 'select2', value: 'key2'},
      { label: 'select3', value: 'key3'}
     ];
     }, 100)
   },
   queryAreaTree() {
    this.config.fieldsConfig[4].options = [
     {
      id: 'a',
      label: 'a',
      children: [{
       id: 'aa',
       label: 'AA',
      }, {
       id: 'ab',
       label: 'AB',
      }],
     }, {
      id: 'b',
      label: 'B',
     }, {
      id: 'c',
      label: 'C',
     }
    ]
   }
  }
 }
</script>

大概就是这样的思路,我们希望我们只要写上面那样子的配置数据就可以动态生成各种这样的表单组件,不用写一大堆重复代码。如果有更好的解决办法,欢迎和我联系。另外,代码路径https://github.com/supportlss/vue-dynamic-form

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
JavaScript 替换Html标签实现代码
Oct 14 Javascript
jQuery ajax BUG:object doesn't support this property or method
Jul 06 Javascript
Google Dart编程语法和基本类型学习教程
Nov 27 Javascript
JQuery中使用Ajax赋值给全局变量异常的解决方法
Jan 10 Javascript
JQuery 控制内容长度超出规定长度显示省略号
May 23 Javascript
jquery实现隐藏在左侧的弹性弹出菜单效果
Sep 18 Javascript
Windows下用PyCharm和Visual Studio开始Python编程
Oct 26 Javascript
jQuery实现仿QQ空间装扮预览图片的鼠标提示效果代码
Oct 30 Javascript
使用JQuery实现的分页插件分享
Nov 05 Javascript
bootstrap datetimepicker日期插件超详细使用方法介绍
Feb 23 Javascript
Node.js实现连接mysql数据库功能示例
Sep 15 Javascript
vue实现商城上货组件简易版
Nov 27 Javascript
小程序实现展开/收起的效果示例
Sep 22 #Javascript
玩转vue的slot内容分发
Sep 22 #Javascript
vue 巧用过渡效果(小结)
Sep 22 #Javascript
vue forEach循环数组拿到自己想要的数据方法
Sep 21 #Javascript
vue2.x集成百度UEditor富文本编辑器的方法
Sep 21 #Javascript
vue中,在本地缓存中读写数据的方法
Sep 21 #Javascript
vuejs中监听窗口关闭和窗口刷新事件的方法
Sep 21 #Javascript
You might like
这部好评如潮的动漫 知名梗频出 但是画风劝退很多人
2020/03/08 日漫
PHP.MVC的模板标签系统(三)
2006/09/05 PHP
PHP中使用sleep造成mysql读取失败的案例和解决方法
2014/08/21 PHP
PHP使用逆波兰式计算工资的方法
2015/07/29 PHP
PHP YII框架开发小技巧之模型(models)中rules自定义验证规则
2015/11/16 PHP
基于PHP微信红包的算法探讨
2016/07/21 PHP
js实现简单锁屏功能实例
2015/05/27 Javascript
基于javascript编写简单日历
2016/05/02 Javascript
javascript事件模型介绍
2016/05/31 Javascript
Angular.JS实现无限级的联动菜单(使用demo)
2017/02/08 Javascript
详解JavaScript按概率随机生成事件
2017/08/02 Javascript
图片加载完成再执行事件的实例
2017/11/16 Javascript
webpack中的热刷新与热加载的区别
2018/04/09 Javascript
一秒学会微信小程序制作table表格
2019/02/14 Javascript
深入解析vue 源码目录及构建过程分析
2019/04/24 Javascript
vue项目中引入vue-datepicker插件的详解
2019/05/14 Javascript
jQuery 图片查看器插件 Viewer.js用法简单示例
2020/04/04 jQuery
原生js实现下拉框选择组件
2021/01/20 Javascript
python实现单向链表详解
2018/02/08 Python
图解Python变量与赋值
2018/04/03 Python
Python之文字转图片方法
2018/05/10 Python
对python 操作solr索引数据的实例详解
2018/12/07 Python
对python使用telnet实现弱密码登录的方法详解
2019/01/26 Python
使用matlab或python将txt文件转为excel表格
2019/11/01 Python
python多线程和多进程关系详解
2020/12/14 Python
python实现视频压缩功能
2020/12/18 Python
css3学习心得分享
2013/08/19 HTML / CSS
使用canvas绘制超炫时钟
2014/12/17 HTML / CSS
Canvas引入跨域的图片导致toDataURL()报错的问题的解决
2018/09/19 HTML / CSS
P D PAOLA意大利官网:西班牙著名的珠宝首饰品牌
2019/09/24 全球购物
烹调加工管理制度
2014/02/04 职场文书
学期评语大全
2014/04/30 职场文书
导游词欢迎词
2015/02/02 职场文书
详解MySQL事务的隔离级别与MVCC
2021/04/22 MySQL
python状态机transitions库详解
2021/06/02 Python
Python语言规范之Pylint的详细用法
2021/06/24 Python