項(xiàng)目背景
最近使用Vue(版本2.9)開發(fā)一個(gè)項(xiàng)目時(shí)卖毁,要生成表單列表池颈,所以使用了v-for來做循環(huán)怀薛,循環(huán)里的元素(item)是一個(gè)子組件刺彩。同時(shí)每個(gè)元素都有刪除按鈕,點(diǎn)擊后刪除當(dāng)前元素枝恋。
初始代碼如下:
父組件:
<template>
<div class="content-body">
<div>任務(wù)</div>
<div>
<ul>
<li v-for="(item,index) in selectionConditionList" :key="index" style="margin:10px 0">
<v-selection-condition-list></v-selection-condition-list> <button @click="deleteSelectionCondition(index)">刪除</button>
</li>
</ul>
</div>
<div>
<button @click="addNewSelectionTask">新建任務(wù)</button>
</div>
</div>
</template>
<script>
/* eslint-disable */
import vSelectionConditionList from './SelectionConditionList'
export default
{
data()
{
return {
selectionConditionList:[],
}
},
methods: {
// 添加新的用戶篩選條件
addNewSelectionTask(){
this.selectionConditionList.push({});
},
// 刪除用戶篩選條件
deleteSelectionCondition(index){
console.log("delete.."+index);
this.selectionConditionList.splice(index,1);
}
},
components:{
vSelectionConditionList
}
}
</script>
<style>
.div_center {
text-align: center;;
width:100%;
margin:0 auto;
}
</style>
子組件:
<template>
<input type="text" :value="inputName">
</template>
<script>
/* eslint-disable */
export default
{
data()
{
return {
inputName: Math.random()
}
},
methods: {
}
}
</script>
出現(xiàn)的問題
運(yùn)行代碼后创倔,點(diǎn)擊新建任務(wù),出現(xiàn)的結(jié)果如下圖:
點(diǎn)擊第一行的刪除按鈕焚碌,預(yù)期當(dāng)然是刪掉第一行三幻。然而出現(xiàn)的結(jié)果卻是最后一行被刪掉了,而其他元素未變呐能。刪除中間某元素也是最后一行被刪掉念搬。這時(shí)通過console控制臺(tái)的打印輸出可以看到,刪除的index索引是正確的摆出。本人是vue新手朗徊,遇到此問題有些懵,查詢官方文檔及百度相關(guān)問題無果后偎漫,在segmentfault問答區(qū)提問爷恳,當(dāng)時(shí)問題鏈接。然鵝提問一天以后象踊,收到的回答還是沒有完全解決問題温亲,于是繼續(xù)尋求解決方案棚壁。
解決方法
經(jīng)過再次苦苦查詢相關(guān)問題的問答帖及文章,終于發(fā)現(xiàn)問題是出在v-for的:key上栈虚。關(guān)于v-for中的:key介紹參見此頁面:Vue2.0 v-for 中 :key 到底有什么用袖外?,內(nèi)容一大堆balabala魂务,總之是由于虛擬DOM的原因引起的曼验,我的理解就是:表單列表的生成是通過綁定的selectionConditionList數(shù)組來生成的,當(dāng)selectionConditionList刪除掉一項(xiàng)時(shí)粘姜,表單列表的dom對(duì)象自然也會(huì)減少一項(xiàng)鬓照。但是由于v-for循環(huán)的是子組件,子組件內(nèi)部顯示數(shù)據(jù)并未綁定selectionConditionList數(shù)組里的屬性孤紧,因此子組件的顯示數(shù)據(jù)并未按新數(shù)組重新渲染豺裆,體現(xiàn)出來的結(jié)果就是最后一個(gè)元素被刪掉了。
解決方法就是給:key賦予一個(gè)獨(dú)一無二的值号显,這樣綁定的數(shù)組就可以和dom對(duì)象一一對(duì)應(yīng)起來臭猜,刪除的時(shí)候也能正確刪除掉響應(yīng)dom對(duì)象了。綁定這個(gè)“獨(dú)一無二”的值咙轩,其中一個(gè)方法就是使用guid,也就是Global Unique Identifier阴颖,于是把生成guid的方法寫到了一個(gè)公共的js文件里活喊,:key綁定guid值,測試ok量愧,大功告成钾菊!
代碼如下:
父組件:
<template>
<div class="content-body">
<div>任務(wù)</div>
<div>
<ul>
<li v-for="(item,index) in selectionConditionList" :key="item.guid" style="margin:10px 0">
<v-selection-condition-list></v-selection-condition-list> <button @click="deleteSelectionCondition(index)">刪除</button>
</li>
</ul>
</div>
<div>
<button @click="addNewSelectionTask">新建任務(wù)</button>
</div>
</div>
</template>
<script>
/* eslint-disable */
import Utils from '../utils/utils.js'
import vSelectionConditionList from './SelectionConditionList'
export default
{
data()
{
return {
selectionConditionList:[],
}
},
methods: {
// 添加新的用戶篩選條件
addNewSelectionTask(){
this.selectionConditionList.push({guid:Utils.guid()});
},
// 刪除用戶篩選條件
deleteSelectionCondition(index){
console.log("delete.."+index);
this.selectionConditionList.splice(index,1);
}
},
components:{
vSelectionConditionList
}
}
</script>
<style>
.div_center {
text-align: center;;
width:100%;
margin:0 auto;
}
</style>
子組件:
<template>
<input type="text" :value="inputName">
</template>
<script>
/* eslint-disable */
export default
{
data()
{
return {
inputName: Math.random()
}
},
methods: {
}
}
</script>
guid方法:
/* eslint-disable */
var utils = {
guid: function() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
var r = Math.random() * 16 | 0,
v = c == 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
}
}
export default utils
后話
此問題只出現(xiàn)在v-for嵌套子組件的情況下。如果是v-for循環(huán)一個(gè)div或表單對(duì)象偎肃,而對(duì)象中的數(shù)據(jù)都是通過數(shù)組中的對(duì)象屬性綁定的煞烫,那么數(shù)組刪除其中一項(xiàng)后,dom對(duì)象列表也可以相應(yīng)正確渲染累颂。有興趣的話可以把子組件換成input對(duì)象滞详,然后在selectionConditionList中添加類似{val:Math.random()}這樣的數(shù)據(jù),實(shí)測刪除后是沒有問題的紊馏。