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 原型模式实现OOP的再研究
Apr 09 Javascript
Javascript 汉字字节判断
Aug 01 Javascript
jQuery 过滤not()与filter()实例代码
May 10 Javascript
jQuery点击自身以外地方关闭弹出层的简单实例
Dec 24 Javascript
JavaScript实现将数组数据添加到Select下拉框的方法
Aug 21 Javascript
jquery捕捉回车键及获取checkbox值与异步请求的方法
Dec 24 Javascript
微信小程序中显示html格式内容的方法
Apr 25 Javascript
彻底解决 webpack 打包文件体积过大问题
Jul 07 Javascript
详解JavaScript 的变量
Mar 08 Javascript
vue--vuex详解
Apr 15 Javascript
如何通过vscode运行调试javascript代码
Jul 24 Javascript
js canvas实现五子棋小游戏
Jan 22 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
通过ICQ网关发送手机短信的PHP源程序
2006/10/09 PHP
php图片验证码代码
2008/03/27 PHP
php 生成唯一id的几种解决方法
2013/03/08 PHP
php简单实现多字节字符串翻转的方法
2015/03/31 PHP
php实现在线通讯录功能(附源码)
2016/05/13 PHP
PHP多进程编程实例详解
2017/07/19 PHP
jquery.simple.tree插件 更简单,兼容性更好的无限树插件
2010/09/03 Javascript
Jquery进度条插件 Progress Bar小问题解决
2011/07/12 Javascript
JS等比例缩小图片尺寸的实例
2013/02/27 Javascript
javascript禁制后退键(Backspace)实例代码
2013/11/15 Javascript
jQuery中:last-child选择器用法实例
2014/12/31 Javascript
JS实现文字放大效果的方法
2015/03/03 Javascript
JavaScript获取网页中第一个图片id的方法
2015/04/03 Javascript
举例讲解Node.js中的Writable对象
2015/07/29 Javascript
JavaScript必知必会(九)function 说起 闭包问题
2016/06/08 Javascript
Javascript类型系统之String字符串类型详解
2016/06/21 Javascript
js手机号4位显示空格,银行卡每4位显示空格效果
2017/03/23 Javascript
基于twbsPagination.js分页插件使用心得(分享)
2017/10/21 Javascript
three.js 将图片马赛克化的示例代码
2020/07/31 Javascript
python中实现定制类的特殊方法总结
2014/09/28 Python
python保存二维数组到txt文件中的方法
2018/11/15 Python
详解python中sort排序使用
2019/03/23 Python
pytorch使用Variable实现线性回归
2019/05/21 Python
python分割一个文本为多个文本的方法
2019/07/22 Python
python requests使用socks5的例子
2019/07/25 Python
东方电视购物:东方CJ
2016/10/12 全球购物
Ted Baker美国官网:英国时尚品牌
2018/10/29 全球购物
下面关于"联合"的题目的输出是什么
2013/08/06 面试题
const和static readonly区别
2013/05/20 面试题
经管应届生求职信
2013/11/17 职场文书
小学四年级学生评语
2014/12/26 职场文书
龙门石窟导游词
2015/02/02 职场文书
2016优秀大学生个人事迹材料范文
2016/03/01 职场文书
2016年庆“七一”主题党日活动总结
2016/04/05 职场文书
vue2实现provide inject传递响应式
2021/05/21 Vue.js
使用Postman测试需要授权的接口问题
2022/06/21 Java/Android