最近項目中遇到的需求是要操做大量的表單,以前的項目中有作過這方的研究,只不過是用jquery來操做。javascript
先簡單說說之前項目A中的應用場景,可能有小夥伴兒也遇到相同的需求。A項目是公司的OA系統中有的項目,是用java的jsp渲染的頁面,需求是要改爲:嵌入APP中顯示,先後端分離, 後端返回的內容,還不能修改, 只是後端同事作了下接口處理,返回給前端的是一大堆的表單數據。前端
每一個表單都有多個字段表示它的屬性:vue
是否可編輯java
表單類型 (text, textarea, select, radio, checkbox, hidden等 )python
與之聯動的其餘表單jquery
。。。
以前的方案就是各個表單類型和字段屬性進行判斷,調用不一樣的UI組件(如時間日曆選擇器等)json
如今遇到的項目,展現類型少不少,第一個想到的就是一樣的方法,不過此次使用的是Vue的雙向綁定。後端
如下是我在python後端項目中的經驗,若是沒有興趣能夠直接看最後的動態表單部分緩存
項目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) } })
通常的需求是:
一個列表,能夠實現列表的動態添加,刪除。
列表中的每一項是動態的表單,表單個數不肯定,
有提交功能,提交或者能夠保存整個表單
保存的表單,經過接口調回後,回填表單,還能夠再次修改、增長、刪除等
<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) } } })
這樣其餘表單值變換的時候都不會影響到我這份模板的數據,問題解決了。若是以爲本文不錯的話,歡迎點贊。若有問題, 你們一塊兒交流和學習