vue2 中如何實現動態表單增刪改查

最近項目中遇到的需求是要操做大量的表單,以前的項目中有作過這方的研究,只不過是用jquery來操做。javascript

項目A

先簡單說說之前項目A中的應用場景,可能有小夥伴兒也遇到相同的需求。A項目是公司的OA系統中有的項目,是用java的jsp渲染的頁面,需求是要改爲:嵌入APP中顯示,先後端分離, 後端返回的內容,還不能修改, 只是後端同事作了下接口處理,返回給前端的是一大堆的表單數據。前端

每一個表單都有多個字段表示它的屬性:vue

  • 是否可編輯java

  • 表單類型 (text, textarea, select, radio, checkbox, hidden等 )python

  • 與之聯動的其餘表單jquery

  • 。。。
    以前的方案就是各個表單類型和字段屬性進行判斷,調用不一樣的UI組件(如時間日曆選擇器等)json

項目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 如何生成動態表單
<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)
        }
    }
})

這樣其餘表單值變換的時候都不會影響到我這份模板的數據,問題解決了。若是以爲本文不錯的話,歡迎點贊。若有問題, 你們一塊兒交流和學習

相關文章
相關標籤/搜索