vue2 中如何实现动态表单增删改查实例


Posted in Javascript onJune 09, 2017

最近项目中遇到的需求是要操作大量的表单,之前的项目中有做过这方的研究,只不过是用jquery来操作。

项目A

先简单说说以前项目A中的应用场景,可能有小伙伴儿也遇到相同的需求。A项目是公司的OA系统中有的项目,是用java的jsp渲染的页面,需求是要改成:嵌入APP中显示,前后端分离, 后端返回的内容,还不能修改, 只是后端同事做了下接口处理,返回给前端的是一大堆的表单数据。

每个表单都有多个字段表示它的属性:

  1. 是否可编辑
  2. 表单类型 (text, textarea, select, radio, checkbox, hidden等 )
  3. 与之联动的其他表单
  4. 。。。之前的方案就是各个表单类型和字段属性进行判断,调用不同的UI组件(如时间日历选择器等)

项目B

现在遇到的项目,展示类型少很多,第一个想到的就是同样的方法,不过这次使用的是Vue的双向绑定。

以下是我在python后端项目中的经验,如果没有兴趣可以直接看最后的动态表单部分

1 python 后端项目中如何引入Vue

项目B用的是python的jinjia2的模板, 同样都是 {{}} 去解析数据,这种情况下怎么办呢?

{% raw %}
<script type="text/x-template" id="dialog-wrap">
<div class="ms-dialog-wrap" v-show="visible">
 <div class="ms-dialog-inner">
  <div class="ms-dialog-title">{{title}}</div>
  <div class="ms-dialog-body">
   <div class="ms-dialog-content">
    <slot></slot>
   </div>
   <div class="ms-dialog-actions">
    <a class="ms-button" @click="cancelAction">取消</a>
    <a class="ms-button ms-success" @click="confirmSuccess">确定</a>
   </div>
  </div>
 </div>
 <div class="ms-overlayer" @click="cancelAction"></div>
</div>
</script>
{% endraw %}

jinjia2中使用 raw 可以阻止解析内部的代码,这样就可以引入我们的vue模板了,这里是我写的一个dialog弹框的组件

2 定义组件

这里以dialog弹窗组件为例子,直接上代码

// dialog弹框
Vue.component('ms-dialog', {
 name: 'ms-dialog',
 template: '#dialog-wrap',
 data: function () {
  return {
  }
 },
 props: {
  title: String,
  value: {
   type: Boolean,
   required: false
  }
 },
 computed: {
  visible: function () {
   return this.value
  }
 },
 watch: {
  visible: function (newVal) {
   if (newVal) {
    document.addEventListener('wheel', this.disabledScroll, false)
   } else {
    document.removeEventListener('wheel', this.disabledScroll, false)
   }
  }
 },
 methods: {
  confirmSuccess: function () {
   this.$emit('confirm-success')
  },
  cancelAction: function () {
   this.$emit('input', false)
  },
  disabledScroll: function (e) {
   e.preventDefault()
  }
 },
 beforeDestroy: function () {
  document.removeEventListener('scroll', this.disabledScroll, false)
 }
})

动态表单组件

一般的需求是:

  1. 一个列表,可以实现列表的动态添加,删除。
  2. 列表中的每一项是动态的表单,表单个数不确定,
  3. 有提交功能,提交或者可以保存整个表单
  4. 保存的表单,通过接口调回后,回填表单,还可以再次修改、增加、删除等

1 如何生成动态表单

<template v-for="item in lists">
   <div class="list-item" v-if="list.type === 'input'">
    <label>用户名</label>
    <input type="text" v-model="item.value" :value="list.defaultValue" class="form-control">
   </div>
   <div class="list-item" v-if="list.type === 'input'">
    <label>密码</label>
    <input type="text" v-model="item.value" :value="list.defaultValue" class="form-control">
   </div>
   <div class="list-item" v-if="list.type === 'textarea'">
    <label>说明</label>
    <textarea rows="3" v-model="item.value" :value="list.defaultValue" class="form-control"></textarea>
   </div>
   <div class="list-item" v-if="list.type === 'select'">
    <label>性别</label>
    <select v-model="list.value" :value="list.defaultValue">
      <option v-for="sub in list.source" :value="sub.value">{{sub.label}}</option>
    </select>
   </div>
</template>

我们的与后端商量好的数据格式可以是这样的;

lists: [{
 type: 'input',
 defaultValue: 'tom',
 value: 'tom'
}, {
 type: 'input',
 defaultValue: '123456',
 value: '123456'
}, {
 type: 'textarea',
 defaultValue: '123456',
 value: '123456'
}, {
 type: 'select',
 defaultValue: '0',
 value: '0',
 source: [{
  value: '1',
  label: '男'
 }, {
  value: '1,
  label: '女'
 }]
}]

这样一个动态模板就生成了,其他更多类型都可以定义。这份模板数据,一般是需要缓存的。因为接下来的 添加操作也需要这份数据。

添加操作

上面的template只是其中一个动态列表。

<div v-for="book in books">
  <template v-for="item in book.lists">
   ......
  </template>
</div>
<div class="actions">
<button @click="add"></button>
</div>

add的方法一般是:

methods: {
 add: function () {
  this.books.push({
  lists: [{
   type: 'input',
   defaultValue: 'tom',
   value: 'tom'
  }, {
   type: 'input',
   defaultValue: '123456',
   value: '123456'
  }, {
   type: 'textarea',
   defaultValue: '123456',
   value: '123456'
  }, {
   type: 'select',
   defaultValue: '0',
   value: '0',
   source: [{
    value: '1',
    label: '男'
   }, {
    value: '1,
    label: '女'
   }]
  }]
 })
 },

这里需要注意的是,如果这份模板的数据,你是通过在data属性中定义的字段去缓存的,那有可能遇到的是你通过添加操作之后的表单的值会,会随着其中的某个表单的值一起联动。

具体原因,猜测是这里的数据已经是变成响应式的了, 又或者你 通过实例化后的值去缓存这份模板数据,可能结果还是这样。
具体代码可能是这样的:

var vm = new Vue({
  data: {
    books: [],
    cacheTemplate: null
  },
  methods: {
    getForms: function (argument) {
      this.$http.post(url, paras).then(res => {
        // 此处缓存了这份模板数据,cacheTemplate中的数据已经变成响应式的了
        this.cacheTemplate = res.body.data
        this.books.push(res.body.data) // 创建第一动态表单列表

        // 或者你是这是定义的的, 此时data中没有cacheTemplate这个值, 
        // 这样定义按理说是非响应式的,但实际情况并非如此,在项目中发现它还是会影响其他表单
        vm.cacheTemplate = res.body.data
        this.books.push(res.body.data) // 创建第一动态表单列表
      }, res => {

      })
    },
    add: function () {
      // 此处你会发现你新创建的表单的值会影响其他表单
      // log出来this.cacheTemplate你会发现里面的值已经发生了变换
      this.books.push(this.cacheTemplate)
    }
  }
})

这里this.cacheTemplate的值为什么会发生变换,没有搞明白, 猜测原因可能是变成响应式了,vue中会实时监控跟踪,对vue原理理解好的小伙伴可以评论告诉我原因。

下面说下我的解决方法: 我不管你是不是响应式的,因为是对象,你才能监控到变换,那我把你变成字符串不就好了。
直接上代码:

var vm = new Vue({
  data: {
    books: [],
    cacheTemplate: null
  },
  methods: {
    getForms: function (argument) {
      this.$http.post(url, paras).then(res => {
        // 此处同样缓存了这份模板数据,不同的是把它变成了字符串
        this.cacheTemplate = JOSN.stringify(res.body)
        this.books.push(res.body) // 创建第一动态表单列表
      }, res => {

      })
    },
    add: function () {
      // 此处转化成json对象,你发现this.cacheTemplate中的值是没有变换的。
      var cacheTemplate = JSON.parse(this.cacheTemplate)
      this.books.push(cacheTemplate)
    }
  }
})

这样其他表单值变换的时候都不会影响到我这份模板的数据,问题解决了。

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

Javascript 相关文章推荐
javascript 隔行换色函数代码
Oct 24 Javascript
jquery插件开发之实现jquery手风琴功能分享
Mar 10 Javascript
Javascript 浮点运算精度问题分析与解决
Mar 26 Javascript
javascript经典特效分享 手风琴、轮播图、图片滑动
Sep 14 Javascript
JavaScript+HTML5实现的日期比较功能示例
Jul 12 Javascript
微信小程序实时聊天WebSocket
Jul 05 Javascript
vue2.0 element-ui中el-select选择器无法显示选中的内容(解决方法)
Aug 24 Javascript
Javascript通过控制类名更改样式
May 24 Javascript
微信公众号平台接口开发 获取access_token过程解析
Aug 14 Javascript
Vue.set 全局操作简单示例
Sep 19 Javascript
React.js组件实现拖拽排序组件功能过程解析
Apr 27 Javascript
详解如何在Javascript中使用Object.freeze()
Oct 18 Javascript
JS创建Tag标签的方法详解
Jun 09 #Javascript
JavaWeb表单及时验证功能在输入后立即验证(含用户类型,性别,爱好...的验证)
Jun 09 #Javascript
JS实现的随机排序功能算法示例
Jun 09 #Javascript
JQuery form表单提交前验证单选框是否选中、删除记录时验证经验总结(整理)
Jun 09 #jQuery
JQuery.dataTables表格插件添加跳转到指定页
Jun 09 #jQuery
基于代数方程库Algebra.js解二元一次方程功能示例
Jun 09 #Javascript
JavaScript 中调用 Kotlin 方法实例详解
Jun 09 #Javascript
You might like
WAR3重制版DOTA 5V5初体验
2020/04/09 DOTA
php在window iis的莫名问题的测试方法
2013/05/14 PHP
php中的路径问题与set_include_path使用介绍
2014/02/11 PHP
PHP中使用Imagick操作PSD文件实例
2015/01/26 PHP
php插入含有特殊符号数据的处理方法
2016/11/24 PHP
PHP从零开始打造自己的MVC框架之路由类实现方法分析
2019/06/03 PHP
jquery实现的元素的left增加N像素 鼠标移开会慢慢的移动到原来的位置
2010/03/21 Javascript
JavaScript 操作table,可以新增行和列并且隔一行换背景色代码分享
2013/07/05 Javascript
js jquery获取随机生成id的服务器控件的三种方法
2013/07/11 Javascript
JavaScript中的标签语句用法分析
2015/02/10 Javascript
javascript实现点击后变换按钮显示文字的方法
2015/05/13 Javascript
高性能JavaScript 重排与重绘(2)
2015/08/11 Javascript
基于JavaScript如何实现私有成员的语法特征及私有成员的实现方式
2015/10/28 Javascript
JavaScript知识点整理
2015/12/09 Javascript
node.js从数据库获取数据
2016/05/08 Javascript
js实现简单的碰壁反弹效果
2016/08/30 Javascript
WebPack基础知识详解
2017/01/16 Javascript
JavaScript中捕获与冒泡详解及实例
2017/02/03 Javascript
微信小程序实现倒计时调用相机自动拍照功能
2018/06/10 Javascript
JavaScript冒泡算法原理与实现方法深入理解
2020/06/04 Javascript
[00:05]ChinaJoy现场 DOTA2玩家高呼“CN DOTA BEST DOTA”
2019/08/04 DOTA
Python 获取当前所在目录的方法详解
2017/08/02 Python
pip install urllib2不能安装的解决方法
2018/06/12 Python
Python 3.8中实现functools.cached_property功能
2019/05/29 Python
python+django+rest框架配置创建方法
2019/08/31 Python
python针对mysql数据库的连接、查询、更新、删除操作示例
2019/09/11 Python
python利用openpyxl拆分多个工作表的工作簿的方法
2019/09/27 Python
Python Django中的STATIC_URL 设置和使用方式
2020/03/27 Python
css3绘制百度的小度熊
2018/10/29 HTML / CSS
一套带网友答案的.NET笔试题
2016/12/06 面试题
《美丽的黄昏》教学反思
2014/02/28 职场文书
个人租房协议书
2014/04/09 职场文书
阅兵口号
2014/06/19 职场文书
群众路线学习心得体会范文
2014/11/05 职场文书
售后服务质量承诺书
2015/04/29 职场文书
家电创业计划书
2019/08/05 职场文书