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控制上传文件的大小
Oct 26 Javascript
JavaScript 无符号右移运算符
Apr 17 Javascript
Jquery实战_读书笔记2 选择器
Jan 22 Javascript
非jQuery实现照片散落桌子上,单击放大的LightBox效果
Nov 28 Javascript
Node.js编程中客户端Session的使用详解
Jun 23 Javascript
form表单转Json提交的方法(推荐)
Sep 23 Javascript
AngularJS基于factory创建自定义服务的方法详解
May 25 Javascript
JavaScript创建对象的七种方式(推荐)
Jun 26 Javascript
详解vue.js数据传递以及数据分发slot
Jan 20 Javascript
JavaScript去掉数组重复项的方法分析【测试可用】
Jul 19 Javascript
vue初始化动画加载的实例
Sep 01 Javascript
JS 正则表达式验证密码、邮箱格式的实例代码
Oct 28 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
Thinkphp3.2.3分页使用实例解析
2016/07/28 PHP
php图形jpgraph操作实例分析
2017/02/22 PHP
js和jquery批量绑定事件传参数一(新猪猪原创)
2010/06/23 Javascript
Ajax异步提交表单数据的说明及方法实例
2013/06/22 Javascript
jquery在项目中做复选框时遇到的一些问题笔记
2013/11/17 Javascript
js replace替换所有匹配的字符串
2014/02/13 Javascript
js获取内联样式的方法
2015/01/27 Javascript
js定义类的几种方法(推荐)
2016/06/08 Javascript
Javascript生成带参数的二维码示例
2016/10/10 Javascript
BootStrap整体框架之基础布局组件
2016/12/15 Javascript
深入学习nodejs中的async模块的使用方法
2017/07/12 NodeJs
webpack实现热更新(实施同步刷新)
2017/07/28 Javascript
Vue单文件组件基础模板小结
2017/08/10 Javascript
Three.js实现浏览器变动时进行自适应的方法
2017/09/26 Javascript
JS中touchstart事件与click事件冲突的解决方法
2018/03/12 Javascript
JS判断字符串是否为整数的方法--简单的正则判断
2018/07/23 Javascript
vue .js绑定checkbox并获取、改变选中状态的实例
2018/08/24 Javascript
详解Vue源码中一些util函数
2019/04/24 Javascript
es6 for循环中let和var区别详解
2020/01/12 Javascript
JS数组方法join()用法实例分析
2020/01/18 Javascript
小程序组件传值和引入sass的方法(使用vant Weapp组件库)
2020/11/24 Javascript
[00:09]DOTA2新版本PA至宝特效动作展示
2014/11/19 DOTA
Python3内置模块之json编解码方法小结【推荐】
2020/12/09 Python
python装饰器使用实例详解
2019/12/14 Python
python except异常处理之后不退出,解决异常继续执行的实现
2020/04/25 Python
tensorflow从ckpt和从.pb文件读取变量的值方式
2020/05/26 Python
python将字典内容写入json文件的实例代码
2020/08/12 Python
scrapy利用selenium爬取豆瓣阅读的全步骤
2020/09/20 Python
python反扒机制的5种解决方法
2021/02/06 Python
澳大利亚工具仓库:Tools Warehouse
2018/10/15 全球购物
医学院护理专业应届生求职信
2013/11/12 职场文书
学生会主席就职演讲稿
2014/01/14 职场文书
安全事故检讨书
2014/01/18 职场文书
村级个人对照检查材料
2014/08/22 职场文书
2014年预备党员端正入党动机思想汇报
2014/09/13 职场文书
优秀共产党员事迹材料
2014/12/18 职场文书