我們知道vue屬于MVVM框架告匠,數(shù)據(jù)操作視圖蛛倦。對data對象中的數(shù)據(jù)進(jìn)行監(jiān)聽捧弃,當(dāng)偵測到數(shù)據(jù)改變時相應(yīng)數(shù)據(jù)所影響的頁面也會觸發(fā)更新许赃。所以我們所需要的這些響應(yīng)式數(shù)據(jù)止喷,受到j(luò)avascript的限制,vue不能檢測到對象屬性的添加或刪除混聊,因為Vue利用的是Object的defineProperty()方法弹谁,在初始化實列時將屬性轉(zhuǎn)為getter/setter,所以屬性必須在data對象上才能讓vue轉(zhuǎn)換它句喜。
當(dāng)然這只是一般的屬性预愤,以一般字符串,數(shù)字咳胃,布爾值這樣的基本數(shù)據(jù)類型作為屬性值的響應(yīng)植康,當(dāng)然我們有時候的訴求的初始化屬性的屬性值不只有這樣的基本數(shù)據(jù)變量,我們還會用到數(shù)組展懈,對象這樣的引用數(shù)據(jù)變量销睁。引用數(shù)據(jù)變量就是對地址的引用供璧,只是對象的指針發(fā)生變化,并沒有重新生成一個對象冻记,此處省略過多其他介紹睡毒,應(yīng)該這些都比較懂。冗栗。演顾。
vue在這種情況下給我們提供了$set這種響應(yīng)式方法去操作頁面更新。其實這只是set簡單的對象不是嵌套很深的那種隅居,那如果是那樣嵌套比較深的那種我們該怎樣去做呢钠至?說多了不如來個業(yè)務(wù)情景然后擼幾行代碼看一下:
這樣的一個場景我們從后臺請求下一個list相當(dāng)于渲染成一個Table,我們需要賦予每行都有自己獨(dú)立的編輯功能和顯示功能。類似于這樣的效果:
當(dāng)然實現(xiàn)效果多種多樣胎源,但我們就當(dāng)后臺給我們的list數(shù)據(jù)是:
[
{
name: '第1行',
textShow: true,
text: ''
},
{
name: '第2行',
textShow: true,
text: ''
},
{
name: '第3行',
textShow: true,
text: ''
},
{
name: '第4行',
textShow: true,
text: ''
我們的頁面為這樣
<template>
<div>
<ul v-if="list">
<li v-for="(item, index) in list" :key="index">
<span>{{item.name}}</span>
<span ref="text" v-show="item.textShow">
{{item.txt}}
</span>
<input type="text" v-model="item.txt" v-show="!item.textShow">
<button @click="edit(item)" v-show="item.showEditBtn">編輯</button>
<button @click="confirm(item)" v-show="!item.showEditBtn">確定</button>
</li>
</ul>
</div>
</template>
當(dāng)然看上面的數(shù)據(jù)機(jī)構(gòu)我們可以看出其實顯示隱藏編輯和確定的數(shù)據(jù)參數(shù)并沒有給咱們棉钧,其實就是我們需要在數(shù)組中對象增加一個新屬性“showEditBtn”去判定:那有時候我們可能會這樣寫:
mounted () {
this.arr.forEach(item => {
item.showEditBtn = true
})
},
當(dāng)我們看頁面效果居然無動于衷,
哈哈!看到上面這種效果赞季,我們應(yīng)該明白了愧捕,showEditBtn屬性并不是初始化在data對象里面的,雖然arr屬于data對象申钩,但你應(yīng)該再好好想想js不能監(jiān)測但對象的變化次绘,當(dāng)然這時候我們可以考慮如何去偵測,必須讓對象變化撒遣。
此時我們可以這樣改寫
mounted () {
this.arr.forEach(item => {
this.$set(item, 'showEditBtn', true)
})
},
這樣他就可以偵測到你對象中的屬性的變化邮偎,當(dāng)然這是一種比較官方的姿勢也是一種比較推薦的姿勢。
我們考慮一下义黎,對象沒有變化我們沒有更新頁面禾进,單純的等號賦值只是引用地址的變化,本身不等于數(shù)組的變化廉涕,那我們讓他的數(shù)組真正變化(重新創(chuàng)建不就可以了)泻云,我們利用Object. assign()去進(jìn)行淺拷貝對象。
mounted () {
this.arr.forEach(item => {
item.showEditBtn = true;
})
this.arr = Object.assign({},this.arr)
},
當(dāng)然這種方式我們可以現(xiàn)效果狐蜕,但我們不如用第一種宠纯,第一種只是單純?nèi)ジ淖円粋€數(shù)組中嵌套的對象的屬性而已,而第二種方法直接淺拷貝的一個數(shù)組對象层释。
當(dāng)然婆瓜,第二種有沒有變通之法,當(dāng)然有贡羔!我們考慮一下廉白,如果之前的功能只是單純的去渲染一個list,
arr: [
{
name: '第1行'
},
{
name: '第2行'
},
{
name: '第3行'
},
{
name: '第4行'
}
沒有編輯功能个初,編輯功能是后來加的,并且遇見的后臺比較懶蒙秒,它就維持這個數(shù)據(jù)結(jié)構(gòu)不變勃黍,那我們是不是有想法了,這樣就啟迪了第二種方式的變通晕讲,
我們不忙著將獲取到的list賦值給arr,我們對他進(jìn)行改寫:
mounted () {
list.forEach(item => {
item.textShow = true;
item.text = ' ';
item.showEditBtn = true;
})
this.arr = list
},
// 同時我們將改寫好的arr放在
<ul v-if="arr">
<li v-for="(item, index) in arr" :key="index">
通過上面的方法我們可以提前預(yù)判我們需要怎樣的數(shù)據(jù)去驅(qū)動視圖马澈,然后我們最先將它初始化在data對象中瓢省,這就需要寫代碼錢我們有個思考全面的過程。
當(dāng)然如果想第一種設(shè)想我們只是單純的去隱藏編輯和確定功能痊班,我們可不可以將在data里去聲明一個單純的全局變量勤婚,不去嵌在數(shù)組和對象那種很隱秘的角落,我想正大光明的成為一個data對象中單獨(dú)的控制變量currentShow涤伐。我們可以分析一下:
因為在寫遍歷列表的時候我們通過v-for循環(huán)去寫馒胆,所以我們?nèi)绻タ刂葡嗤δ茉氐娘@示隱藏,我們引用全局變量currentShow凝果,當(dāng)我們觸發(fā)某個行為去改變currentShow的值時祝迂,我們會發(fā)現(xiàn)所有的item都會相應(yīng)的變化,雖然你操作的是其中一個:
當(dāng)然我們想想因為我們?nèi)值腸urrentShow變量是完全變化一致的器净,我們要想單獨(dú)去操作每行元素型雳,我們該怎樣去做?其實也很簡單山害,我們再加個判斷纠俭,同時滿足這兩個結(jié)果才會觸發(fā)行為,這個判斷必須是每行獨(dú)一無二的浪慌,哈哈冤荆!肯定是index索引了,我們可以再聲明一個data對象屬性currentIndex权纤,當(dāng)我們對每行進(jìn)行操作時钓简,我們將this.currentIndex等于這行的索引,我們增加的判斷就可以變成
v-show="currentIndex === index && currentShow"
每行變化時currentIndex都在變化妖碉,他只能等于操作行的索引涌庭,感覺有一種借力打力的效果。不過實現(xiàn)了
以上雖不是難的東西欧宜,但貴在舉一反三坐榆,簡書記之!H呷住席镀!