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 相关文章推荐
可简单避免的三个JS发布错误的详细介绍
Aug 02 Javascript
分享五个有用的jquery小技巧
Oct 08 Javascript
使用JQuery实现Ctrl+Enter提交表单的方法
Oct 22 Javascript
js Canvas绘制圆形时钟教程
Feb 06 Javascript
webpack学习--webpack经典7分钟入门教程
Jun 28 Javascript
详解使用VueJS开发项目中的兼容问题
Aug 02 Javascript
Vue文件配置全局变量的实例
Sep 06 Javascript
微信小程序新手教程之页面打开数量限制
Mar 03 Javascript
vue自定义指令directive的使用方法
Apr 07 Javascript
解决layer弹出层中表单不起作用的问题
Sep 09 Javascript
Layui表格行工具事件与数据回填方法
Sep 13 Javascript
Vue学习之axios的使用方法实例分析
Jan 06 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
各种快递查询--Api接口
2016/04/26 PHP
PHP序列化操作方法分析
2016/09/28 PHP
简单实用的js调试logger组件实现代码
2010/11/20 Javascript
一个分享按钮的插件使用介绍(可扩展,内附开发制作流程)
2011/09/19 Javascript
非常有用的40款jQuery 插件推荐(系列二)
2011/12/25 Javascript
在JavaScript中typeof的用途介绍
2013/04/11 Javascript
基于Node.js + WebSocket打造即时聊天程序嗨聊
2016/11/29 Javascript
Angularjs 动态改变title标题(兼容ios)
2016/12/29 Javascript
JavaScript监听手机物理返回键的两种解决方法
2017/08/14 Javascript
微信小程序button组件使用详解
2018/01/31 Javascript
小程序实现发表评论功能
2018/07/06 Javascript
Javascript读写cookie的实例源码
2019/03/16 Javascript
通过实例解析chrome如何在mac环境中安装vue-devtools插件
2020/07/10 Javascript
详解python并发获取snmp信息及性能测试
2017/03/27 Python
Python反射用法实例简析
2017/12/22 Python
Python常见数据结构之栈与队列用法示例
2019/01/14 Python
Python中三元表达式的几种写法介绍
2019/03/04 Python
Python3.6实现带有简单界面的有道翻译小程序
2019/04/16 Python
Python编程实现tail-n查看日志文件的方法
2019/07/08 Python
python networkx 根据图的权重画图实现
2019/07/10 Python
在pycharm下设置自己的个性模版方法
2019/07/15 Python
详解pandas中MultiIndex和对象实际索引不一致问题
2019/07/23 Python
Python检查 云备份进程是否正常运行代码实例
2019/08/22 Python
Python之指数与E记法的区别详解
2019/11/21 Python
python 实现turtle画图并导出图片格式的文件
2019/12/07 Python
实现CSS3中的border-radius(边框圆角)示例代码
2013/07/19 HTML / CSS
Hashtable 添加内容的方式有哪几种,有什么区别?
2012/04/08 面试题
机械工程师的岗位职责
2013/11/17 职场文书
材料加工工程求职信
2014/02/19 职场文书
暑期培训随笔感言
2014/03/10 职场文书
会计人员岗位职责
2014/03/19 职场文书
经济贸易专业自荐信
2014/06/11 职场文书
领导走群众路线整改措施思想汇报
2014/10/12 职场文书
离婚财产分配协议书
2014/10/21 职场文书
勇敢的心观后感
2015/06/09 职场文书
《植树问题》教学反思
2016/03/03 职场文书