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实现的鼠标链接提示效果生成器代码
Jun 28 Javascript
jquery多浏览器捕捉回车事件代码
Jun 22 Javascript
JavaScript.Encode手动解码技巧
Jul 14 Javascript
一个简单的瀑布流效果(主体形式自写)
May 27 Javascript
JS计算网页停留时间代码
Apr 28 Javascript
使用Chrome调试JavaScript的断点设置和调试技巧
Dec 16 Javascript
Bootstrap 3.x打印预览背景色与文字显示异常的解决
Nov 06 Javascript
Angular 4依赖注入学习教程之InjectToken的使用(八)
Jun 04 Javascript
vue之数据交互实例代码
Jun 20 Javascript
JSON创建键值对(key是中文或者数字)方式详解
Aug 24 Javascript
使用原生js封装的ajax实例(兼容jsonp)
Oct 12 Javascript
关于jquery layui弹出层的使用方法
Apr 21 jQuery
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
PHP 开发环境配置(Zend Server安装)
2010/04/28 PHP
学习PHP Cookie处理函数
2016/08/09 PHP
PHP实现驼峰样式字符串(首字母大写)转换成下划线样式字符串的方法示例
2017/08/10 PHP
Laravel实现短信注册的示例代码
2018/05/29 PHP
复制Input内容的js代码_支持所有浏览器,修正了Firefox3.5以上的问题
2010/06/21 Javascript
jQuery事件绑定.on()简要概述及应用
2013/02/07 Javascript
javascript获取下拉列表框当中的文本值示例代码
2013/07/31 Javascript
jQuery插件Elastislide实现响应式的焦点图无缝滚动切换特效
2015/04/12 Javascript
JavaScript中解决多浏览器兼容性23个问题的快速解决方法
2016/05/19 Javascript
浅谈JavaScript正则表达式-非捕获性分组
2017/03/08 Javascript
搭建简单的nodejs http服务器详解
2017/03/09 NodeJs
Nodejs中使用captchapng模块生成图片验证码
2017/05/18 NodeJs
Node.js 的模块知识汇总
2017/08/16 Javascript
Vue2.0父组件与子组件之间的事件发射与接收实例代码
2017/09/19 Javascript
微信小程序 上传头像的实例详解
2017/10/27 Javascript
vue树形结构获取键值的方法示例
2018/06/21 Javascript
vue-router中scrollBehavior的巧妙用法
2018/07/09 Javascript
vuejs2.0运用原生js实现简单拖拽元素功能
2020/08/21 Javascript
vue实现压缩图片预览并上传功能(promise封装)
2019/01/10 Javascript
小程序实现层叠卡片滑动效果
2019/08/26 Javascript
layui实现把数据表格时间戳转换为时间格式的例子
2019/09/12 Javascript
二种python发送邮件实例讲解(python发邮件附件可以使用email模块实现)
2013/12/03 Python
python编程实现归并排序
2017/04/14 Python
Python读取Excel表格,并同时画折线图和柱状图的方法
2018/10/14 Python
python 实现分页显示从es中获取的数据方法
2018/12/26 Python
对python中Json与object转化的方法详解
2018/12/31 Python
Python自定义一个异常类的方法
2019/06/27 Python
Python 使用PyQt5 完成选择文件或目录的对话框方法
2019/06/27 Python
使用python画社交网络图实例代码
2019/07/10 Python
Django项目中实现使用qq第三方登录功能
2019/08/13 Python
python实现抠图给证件照换背景源码
2019/08/20 Python
h5网页水印SDK的实现代码示例
2019/02/19 HTML / CSS
村容村貌整治方案
2014/05/21 职场文书
2015年社区关工委工作总结
2015/04/03 职场文书
中学社团活动总结
2015/05/07 职场文书
Android开发实现极为简单的QQ登录页面
2022/04/24 Java/Android