溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

vue2 中如何實現(xiàn)動態(tài)表單增刪改查實例

發(fā)布時間:2020-08-30 17:31:05 來源:腳本之家 閱讀:225 作者:而立先生 欄目:web開發(fā)

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

項目A

先簡單說說以前項目A中的應(yīng)用場景,可能有小伙伴兒也遇到相同的需求。A項目是公司的OA系統(tǒng)中有的項目,是用java的jsp渲染的頁面,需求是要改成:嵌入APP中顯示,前后端分離, 后端返回的內(nèi)容,還不能修改, 只是后端同事做了下接口處理,返回給前端的是一大堆的表單數(shù)據(jù)。

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

  1. 是否可編輯
  2. 表單類型 (text, textarea, select, radio, checkbox, hidden等 )
  3. 與之聯(lián)動的其他表單
  4. 。。。之前的方案就是各個表單類型和字段屬性進行判斷,調(diào)用不同的UI組件(如時間日歷選擇器等)

項目B

現(xiàn)在遇到的項目,展示類型少很多,第一個想到的就是同樣的方法,不過這次使用的是Vue的雙向綁定。

以下是我在python后端項目中的經(jīng)驗,如果沒有興趣可以直接看最后的動態(tài)表單部分

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

項目B用的是python的jinjia2的模板, 同樣都是 {{}} 去解析數(shù)據(jù),這種情況下怎么辦呢?

{% 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 可以阻止解析內(nèi)部的代碼,這樣就可以引入我們的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)
 }
})

動態(tài)表單組件

一般的需求是:

  1. 一個列表,可以實現(xiàn)列表的動態(tài)添加,刪除。
  2. 列表中的每一項是動態(tài)的表單,表單個數(shù)不確定,
  3. 有提交功能,提交或者可以保存整個表單
  4. 保存的表單,通過接口調(diào)回后,回填表單,還可以再次修改、增加、刪除等

1 如何生成動態(tài)表單

<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>

我們的與后端商量好的數(shù)據(jù)格式可以是這樣的;

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: '女'
 }]
}]

這樣一個動態(tài)模板就生成了,其他更多類型都可以定義。這份模板數(shù)據(jù),一般是需要緩存的。因為接下來的 添加操作也需要這份數(shù)據(jù)。

添加操作

上面的template只是其中一個動態(tài)列表。

<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: '女'
   }]
  }]
 })
 },

這里需要注意的是,如果這份模板的數(shù)據(jù),你是通過在data屬性中定義的字段去緩存的,那有可能遇到的是你通過添加操作之后的表單的值會,會隨著其中的某個表單的值一起聯(lián)動。

具體原因,猜測是這里的數(shù)據(jù)已經(jīng)是變成響應(yīng)式的了, 又或者你 通過實例化后的值去緩存這份模板數(shù)據(jù),可能結(jié)果還是這樣。
具體代碼可能是這樣的:

var vm = new Vue({
  data: {
    books: [],
    cacheTemplate: null
  },
  methods: {
    getForms: function (argument) {
      this.$http.post(url, paras).then(res => {
        // 此處緩存了這份模板數(shù)據(jù),cacheTemplate中的數(shù)據(jù)已經(jīng)變成響應(yīng)式的了
        this.cacheTemplate = res.body.data
        this.books.push(res.body.data) // 創(chuàng)建第一動態(tài)表單列表

        // 或者你是這是定義的的, 此時data中沒有cacheTemplate這個值, 
        // 這樣定義按理說是非響應(yīng)式的,但實際情況并非如此,在項目中發(fā)現(xiàn)它還是會影響其他表單
        vm.cacheTemplate = res.body.data
        this.books.push(res.body.data) // 創(chuàng)建第一動態(tài)表單列表
      }, res => {

      })
    },
    add: function () {
      // 此處你會發(fā)現(xiàn)你新創(chuàng)建的表單的值會影響其他表單
      // log出來this.cacheTemplate你會發(fā)現(xiàn)里面的值已經(jīng)發(fā)生了變換
      this.books.push(this.cacheTemplate)
    }
  }
})

這里this.cacheTemplate的值為什么會發(fā)生變換,沒有搞明白, 猜測原因可能是變成響應(yīng)式了,vue中會實時監(jiān)控跟蹤,對vue原理理解好的小伙伴可以評論告訴我原因。

下面說下我的解決方法: 我不管你是不是響應(yīng)式的,因為是對象,你才能監(jiān)控到變換,那我把你變成字符串不就好了。
直接上代碼:

var vm = new Vue({
  data: {
    books: [],
    cacheTemplate: null
  },
  methods: {
    getForms: function (argument) {
      this.$http.post(url, paras).then(res => {
        // 此處同樣緩存了這份模板數(shù)據(jù),不同的是把它變成了字符串
        this.cacheTemplate = JOSN.stringify(res.body)
        this.books.push(res.body) // 創(chuàng)建第一動態(tài)表單列表
      }, res => {

      })
    },
    add: function () {
      // 此處轉(zhuǎn)化成json對象,你發(fā)現(xiàn)this.cacheTemplate中的值是沒有變換的。
      var cacheTemplate = JSON.parse(this.cacheTemplate)
      this.books.push(cacheTemplate)
    }
  }
})

這樣其他表單值變換的時候都不會影響到我這份模板的數(shù)據(jù),問題解決了。

以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持億速云。

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI