在 Vue 中多表單深層次嵌套結構,創建響應式屬性,以及多層級表單驗證

在 Vue 中多表單深層次嵌套結構,創建響應式屬性,以及多層級表單驗證

設置響應式屬性

在 Vue 中,只有在跟級別中創建的屬性,才具有響應式,如果後期手動添加,如使用 this.xxx = xxx這種方式創建的屬性是不具有響應式的。
在 Vue裏面,封裝了 7 個方法,使用如下的方法來添加屬性,同樣可以創建響應式屬性,並觸發視圖更新:

  • push()
  • pop()
  • shift()
  • unshift()
  • splice()
  • sort()
  • reverse()

如果不使用以上的方法,Vue 也提供了$set方法來設置響應式屬性,使用方式爲this.$set(obj, newObj, value),在 Vue 的單文件組件裏,大概是這樣寫的:

<script>
export default {
	data() {
		return {
			obj: {}
		}
	},
	
	methods: {
		setValue() {
			this.$set(this.obj, 'name', 'tim')
		}
	}
}
</script>

以上的代碼表示,在 obj 裏面,添加一個名爲 name 值爲 value的屬性。添加完之後,data 裏面應該是這樣的:

data() {
	return {
		obj: {
			name: 'tim'
		}
	}
}

爲了驗證一下有效性,我們新建一個組件,ui 框架選用 element,來測試一下到底是否可行:

<template>
    <div class="test">
        <el-form ref="form" :model="form" label-width="80px">
            <el-form-item label="name">
                <el-input v-model="form.name"></el-input>
            </el-form-item>
        </el-form>

        <el-button type="primary" @click="testFun">test</el-button>
    </div>
</template>

<script>
export default {
    name: 'test',
    data() {
        return {
            form: {
                
            }
        }
    },
    methods: {
        testFun() {
            this.form.name = 'tim'
        }
    }
}
</script>

<style scoped></style>

先點擊 test 按鈕,我們往 form 裏面添加了 name 屬性,然後在表單輸入值,發現輸入不進去,打開 devtools 發現值也沒有改變。

我們把 testFun 函數改寫一下:

testFun() {
    this.$set(this.form, 'name' 'tim')
}

這回在測試一下,先點擊 test 按鈕,然後發現表單被賦上值了,然後修改表單同樣能夠更新值。

以上表示,如果我們沒有一開始在 data 裏面創建跟級別的屬性,需要使用 $set 來創建。


不過我們要說的不止是這個,而是創建多層嵌套的二維三維數組和對象的響應式,並觸發視圖更新。實際應用主要在表單的多層嵌套上,需要復原數據的情況下

現在假設我們需要復原的數據爲如下格式:

let copyData = [
    [
        {
            name: 'tim',
            age: 10
        },
        {
            name: 'tim',
            age: 20
        }
    ],
    [
        {
            name: 'andy',
            age: 15
        },
        {
            name: 'andy',
            age: 30
        },
    ]
]

這裏面,既有數組又有對象,基本能把創建多維數據的響應式屬性講清楚。對於創建響應式數組和對象的原理,可以點擊這裏查看官網的介紹(建議看一眼之後,再來看這個例子),在此只提供實例進行講解。

  1. 首先,我們先創建一個初始化頁面,一般來說,我們不可能創建一個空的表單 data,所以需要填入屬性,只不過沒有值而已。
<template>
  <div class="test">
    <el-form ref="form" :model="form" label-width="80px">
      <div class="parent" v-for="(parent, index) in form.list" :key="`parent-${index}`">
        <div class="child" v-for="(child, idx) in parent" :key="`child-${idx}`">
          <el-form-item label="name">
            <el-input v-model="child.name"></el-input>
          </el-form-item>
          <el-form-item label="age">
            <el-input v-model="child.age"></el-input>
          </el-form-item>
        </div>
      </div>
    </el-form>

    <el-button type="primary" @click="testFun">test</el-button>
  </div>
</template>

<script>
export default {
  name: "test",
  data() {
    return {
      form: {
        list: [
          [
            {
              name: "",
              age: ""
            }
          ]
        ]
      }
    };
  },
};
</script>

<style scoped></style>	

以上是完整的一個單 Vue 文件。主要是初始化了一個嵌套的多層級表單。
在這裏插入圖片描述
在這裏插入圖片描述

如上,我們在表單裏修改內容,在 devtools 裏面,可以看到值能夠更新
2. 有了以上的佈局結構,我們就可以模擬數據了。

let copyData = {
  list: [
    [
      {
        name: "tim",
        age: 10
      },
      {
        name: "tim",
        age: 20
      }
    ],
    [
      {
        name: "andy",
        age: 15
      },
      {
        name: "andy",
        age: 30
      }
    ]
  ]
};

假設我們通過接口獲取到如上數據,然後我們需要把如上的數據寫入到頁面裏面,那麼我們直接通過 this.form = copyData 只有第一層級的基礎數據結構有效果(Boolean、String、Number),其他是沒有效果的(Array,Object),也就是說,在多層級嵌套的情況下,我們需要通過 Vue 提供的上述 7 種方法,或者 $set 來設置響應式屬性。

  1. 這次我們使用 $set 來完成響應式屬性的設置。

    首先我們看 copyData 裏面的 list,是一個數組,所以我們需要使用 $set 來完成對數組的操作。

    你也可以使用 vm.setVue.set:vm.set 實例方法,該方法是全局方法 Vue.set 的一個別名: vm.set(vm.items, indexOfItem, newValue)

    上面的vm.items其實就是要設置的對象,indexOfItem我們可以通過遍歷 list 來獲取 indexnewValue 就是對應的值。

    copyData.list.forEach((parent, index) => {
       this.$set(this.form.list, index, copyData.list[index]);
     });
    

通過以上代碼,我們點擊 test按鈕,發現頁面會觸發更新,同時渲染出對應的的內容。表明我們設置成功了,如果還有在深層次的嵌套,同樣需要依次遍歷對應的值,然後使用$set設置即可。

表單驗證

對於 element-ui 的表單驗證,我們需要在 html 上添加一些屬性

<div class="test">
    <el-form ref="form" :model="form" label-width="80px" :rules="rules">
      <div class="parent" v-for="(parent, index) in form.list" :key="`parent-${index}`">
        <div class="child" v-for="(child, idx) in parent" :key="`child-${idx}`">
          <el-form-item label="name" prop="name">
            <el-input v-model="child.name"></el-input>
          </el-form-item>
          <el-form-item label="age">
            <el-input v-model="child.age"></el-input>
          </el-form-item>
        </div>
      </div>
    </el-form>
    <el-button type="primary" @click="testFun">test</el-button>
  </div>

// ...script
// data
rules: {
   name: {
     required: true,
     message: "請輸入值",
     trigger: "blur"
   }
 }
  1. 第一步,首先在 el-form上,添加 :rules="xxx",xxx 可以隨便設置,這裏我設置爲 rules
  2. 第二部,在要驗證的表單item 上,添加prop,這個 prop 對應 rules 裏面的值,這裏設置爲 name

其實到這裏已經設置完了,我們發現,在只有一個 name 表單的情況下,能夠正常驗證(沒有通過 v-for 遍歷),但是如果是多個表單同時都指向 name 呢 ?

所以我們可以在單個的表單域上傳遞屬性的驗證規則:

<el-form-item
    label="name"
     :prop="`list.${index}.${idx}.name`"
     :rules="{ required: true, message: '請輸入郵箱地址', trigger: 'blur' }">
  <el-input v-model="child.name"></el-input>
</el-form-item>

rules 上,我們設置爲單獨的 rules,而 prop比較麻煩,需要以 index. 的方式來取對應的字段,這裏需要注意。

那麼通過以上設置後,我們就可以對每個 name 字段分別進行驗證了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章