Vue列表渲染中的key值的重要性

1 .index值不是一定不變的,如果不加key值的話,刪除前面的項(xiàng)。后面的index可能變也可能不變,比如加個(gè)定時(shí)器的時(shí)候會(huì)變,不加定時(shí)器不會(huì)變
2 .不加key的話,更新機(jī)制的進(jìn)行diff的時(shí)候是會(huì)全部比較的,比如刪除第一個(gè)的話,后面的元素其實(shí)都不一樣,會(huì)一項(xiàng)一項(xiàng)的比較。然后全部元素都替換,沒有做到最小更新。而且里面的傳的值也會(huì)變,如果這個(gè)時(shí)候你要根據(jù)里面的值刪除元素的話,就會(huì)出錯(cuò),尤其是加了定時(shí)器之后
3 .所以這個(gè)key值對(duì)數(shù)據(jù)改變之后的diff更新比較有很大的性能提升,或者說有了key和沒有key是兩種比較和更新機(jī)制
4 .使用v-for更新已渲染的元素列表時(shí),默認(rèn)采用舊地復(fù)用策略,會(huì)復(fù)用之前的元素,有的時(shí)候使用index來做為key值,其實(shí)不是特別推薦的??赡軙?huì)發(fā)生變化,最好是時(shí)間戳加上一個(gè)自增的數(shù)字

5 .如果有key的話,就會(huì)根據(jù)key值去判斷某個(gè)是否修改,重新渲染這一項(xiàng)

6 .虛擬dom的diff算法

1 .兩個(gè)相同的組件產(chǎn)生類似的dom結(jié)構(gòu),不同的組件產(chǎn)生不同的dom結(jié)構(gòu)
2 .同一層級(jí)的一組節(jié)點(diǎn),可以通過唯一的id進(jìn)行區(qū)分
3 .當(dāng)一層有很多相同的節(jié)點(diǎn)的時(shí)候,也就是列表節(jié)點(diǎn)時(shí),diff算法的更新過程默認(rèn)情況是遵循以上原則
4 .如果數(shù)據(jù)的順序被改變,Vue將不會(huì)移動(dòng)DOM元素在匹配數(shù)據(jù)項(xiàng)的順序,而是”就地更新“的策略。

7 .就地復(fù)用的弊端

1 .雖然很高效,但是只適合與不依賴子組件狀態(tài)或者臨時(shí)的dom
2 .一旦要求新加入元素的狀態(tài),就會(huì)出問題
3 .
16401a8ca6f8c764.jpg

1 .當(dāng)我們想把一個(gè)f插入到b,c之間,默認(rèn)是這樣的


16401a8ca73549bb.jpg

2 .一個(gè)頂一個(gè),并不是我們想象的那樣,同理,刪除的時(shí)候也是這樣(c->f,d-c,e-d,然后插入e)
3 .但是如果我們給他加了key值之后


16401a8ca6d7e50c.jpg

4 .diff算法就可以正確的識(shí)別此節(jié)點(diǎn),找到正確的位置并插入新的節(jié)點(diǎn)
5 .key的作用是為了更加高效的更新虛擬do'm,另外在vue中使用相同標(biāo)簽元素的過度切換的時(shí)候,也需要使用key屬性,其目的是為了讓vue區(qū)分它們,否則vueh就只會(huì)替換其內(nèi)部屬性而不會(huì)觸發(fā)過度效果

第二波

1 .當(dāng)頁面的數(shù)據(jù)發(fā)生變化的時(shí)候,diff算法知乎i比較同一層級(jí)的節(jié)點(diǎn)

1 .如果節(jié)點(diǎn)類型不同,直接干掉前面的節(jié)點(diǎn),在創(chuàng)建并插入新的節(jié)點(diǎn),不會(huì)在比較這個(gè)節(jié)點(diǎn)以后的子節(jié)點(diǎn)了
2 .如果節(jié)點(diǎn)類型相同,重新設(shè)置該節(jié)點(diǎn)的屬性,從而實(shí)現(xiàn)節(jié)點(diǎn)的更新
3 .所以,當(dāng)某一層有很多相同的節(jié)點(diǎn)的時(shí)候,diff的默認(rèn)是遵循第二條的

2 .對(duì)象遍歷渲染的時(shí)候,是按照Object.keys()結(jié)果遍歷的,所以不能保證絕對(duì)的順序。所以最好是按照數(shù)組里面包含對(duì)象的方法來渲染,這樣可以保證絕對(duì)的順序
3 .官方文檔的明確顯示的部分

1 .當(dāng)使用v-for更新已經(jīng)渲染過的元素列表時(shí),默認(rèn)的使用”舊地復(fù)用“策略,如果數(shù)據(jù)項(xiàng)的順序被改變,Vue是不會(huì)移動(dòng)dom來匹配數(shù)據(jù)項(xiàng)的順序,而是簡單的復(fù)用此處的每個(gè)元素,并且確保他在特定索引下顯示已被渲染過的元素
2 .這個(gè)模式默認(rèn)是高效的,但是只適用于不依賴子組件狀態(tài)或臨時(shí)DOM鉆港臺(tái),比如列表渲染輸出
3 .為了給Vue一個(gè)提示,使他可以追蹤每個(gè)節(jié)點(diǎn)的身份,從而重用和重新排序現(xiàn)有元素,這就需要為每一個(gè)項(xiàng)提供一個(gè)唯一的key屬性
4 .注意:不添加key的性能其實(shí)更加優(yōu)秀。除了想要性能或者輸出非常的內(nèi)容非常簡單
5 .不要使用對(duì)象或者數(shù)組之類的非原始值作為v-for的key,用字符串或者整數(shù)類型的值來取代

4 .數(shù)據(jù)的這些方法會(huì)返回一個(gè)新的數(shù)據(jù),也就是說當(dāng)調(diào)用這些方法的時(shí)候需要使用新數(shù)組替換舊的數(shù)組。Vue為了使得dom元素得到最大范圍的重用而實(shí)現(xiàn)了一些智能的,啟發(fā)式的方法。也就是說,用一個(gè)含有相同元素的數(shù)據(jù)去替換原來的數(shù)據(jù)會(huì)有非常高效的操作

5 .不能檢測(cè)到的變化:數(shù)組里面使用索引設(shè)置一個(gè)項(xiàng)時(shí),包括對(duì)象添加新的值的時(shí)候,所以這兩種情況都需要使用特定的方法。只不過是不支持常用的用法罷了,當(dāng)時(shí)為什么不加個(gè)語法糖呢。。
6 .同一個(gè)元素里面v-for和v-if的優(yōu)先級(jí),v-if將運(yùn)行于每一個(gè)v-for循環(huán)中,當(dāng)想根據(jù)某些條件在渲染一些dom的時(shí)候,舊可以使用這個(gè)
7 . v-if當(dāng)父元素 v-for當(dāng)子元素

v-if中的key

1 .v-if中想要渲染多個(gè)元素的時(shí)候,可以把一個(gè)template元素當(dāng)成不可見的包裹元素,并在上面使用v-if,最終的渲染結(jié)果將不會(huì)包括template元素
2 .為了盡可能高效的渲染元素,通常會(huì)復(fù)用已有元素而不是從頭開始渲染,除了更快,還以一些其他的好處

1 .以下是沒有key的時(shí)候
2 .input切換的時(shí)候,會(huì)保留之前填的表格
3 .

3 .添加一個(gè)key值,vue就知道這兩個(gè)元素是完全不一樣的,所以創(chuàng)建的時(shí)候直接從0開始,而不是復(fù)用
4 .但是如果其他的地方?jīng)]加key,也是會(huì)復(fù)用的。所以要在合適的位置加上key
5 .v-show:帶有v-show的元素始終會(huì)被渲染并保留在dom中,v-show只是簡單的切換css屬性display
6 .不支持template,也不支持v-else

比較v-show,v-if

1 .v-if是真正的條件渲染因?yàn)樗_保在切換過程中條件塊內(nèi)的事件監(jiān)聽器和子組件適當(dāng)?shù)谋讳N毀和重建
2 .v-if也是惰性的,如果在初始渲染時(shí)條件為假,則什么都不做,直到條件第一次變?yōu)檎妫艜?huì)開始渲染條件塊
3 .v-show:不管是什么條件,都是會(huì)被渲染,只是簡單的進(jìn)行css切換
4 .v-if有更高的切換開銷,v-show有更高的初始渲染開銷。如果需要頻繁的切換,使用v-show,如果在運(yùn)行時(shí)條件很少改變,則使用v-if較好
5 .

第三波,為什么加了key還是會(huì)復(fù)用呢,沒有走到mounted生命周期

//父組件
<template>
    <div>
        <h1 @click="handleAdd">+</h1>
        <h1 @click="handleRem">-</h1>
        <test v-for="c in test_arr" :value="c.value" :key="c.id"/>
    </div>
</template>
<script>
    import test from './son/test'
    export default{
        data:function(){
            return {
                arr:[
                    {
                        id:1,
                        value:1
                    },
                    {
                        id:2,
                        value:2
                    },
                    {
                        id:3,
                        value:3
                    },
                    {
                        id:4,
                        value:4
                    },
                    {
                        id:5,
                        value:5
                    },
                    {
                        id:6,
                        value:6
                    },
                    {
                        id:7,
                        value:7
                    },
                    {
                        id:8,
                        value:8
                    },
                    {
                        id:9,
                        value:9
                    },
                    {
                        id:10,
                        value:10
                    },
                    {
                        id:11,
                        value:11
                    },
                    {
                        id:12,
                        value:12
                    },
                    {
                        id:13,
                        value:13
                    },
                    {
                        id:14,
                        value:15
                    },
                    {
                        id:15,
                        value:15
                    },

                ],
                test_arr:[],
                start:0
            }
        },
        methods:{
            handleAdd(){
                this.start++
                this.test_arr=this.arr.slice(this.start,this.start+3)
            },
            handleRem(){
                this.start--
                this.test_arr=this.arr.slice(this.start,this.start+3)
            }
        },
        components:{
            test,
        }
    }
</script>

1 .在第一次v-for中,不加key的話,如果數(shù)據(jù)改變的話,其實(shí)走的是復(fù)用的邏輯,并不走的第一次從新渲染的步驟,也就是沒有新創(chuàng)建dom結(jié)構(gòu),僅僅是替換了元素,那么這個(gè)時(shí)候,當(dāng)我想根據(jù)新傳入的數(shù)據(jù)做一些操作的行為就不會(huì)觸發(fā)。其實(shí)這個(gè)情況是前后數(shù)據(jù)結(jié)構(gòu)一樣的。那如果前后數(shù)據(jù)結(jié)構(gòu)不一樣,必然有新創(chuàng)建dom的情況,也不會(huì)觸發(fā)mounted事件么?測(cè)試發(fā)現(xiàn),真的是不會(huì)觸發(fā)的

2 .然后我們加上了key值,現(xiàn)在進(jìn)行數(shù)據(jù)改變,這時(shí)發(fā)現(xiàn),之后每一次變化的元素,才會(huì)觸發(fā)mounted事件,也就是說,如果之前是顯示在第二個(gè)的元素,現(xiàn)在數(shù)據(jù)發(fā)生變化之后,我們是沒辦法知道新的第一個(gè)元素的數(shù)據(jù),僅僅是通過mounted事件,只有新加入的元素,才會(huì)觸發(fā)mounted事件

3 .那這個(gè)時(shí)候我們就需要使用一個(gè)新的生命周期函數(shù),update。比如以下場(chǎng)景:當(dāng)傳入組件的某一個(gè)值發(fā)生了變化,導(dǎo)致渲染元素的高度發(fā)生了變化,而我們又恰恰想知道新的高度。這個(gè)時(shí)候就需要在updated生命周期函數(shù)里面觸發(fā),然后改變記得這個(gè)變量
4 .這里其實(shí)第一次想的還是有點(diǎn)問題的,新加入的元素直接就新建就可以,不需要在復(fù)用dom,重新渲染,然后在算一遍高度了。

//子組件
<template>
    <div>
        {{value}}
    </div>
</template>
<script>
export default {
    props:{
        value:{
            type:Number,
        }
    },
    mounted(){
        console.log('加載了一次')
        console.log(this.value)
    }
}
</script>

總結(jié)

1 .key的作用是用來對(duì)比組件自身新舊DOM進(jìn)行更新的,跟蹤節(jié)點(diǎn)身份
2 .key的作用是輔助判斷新舊vdom節(jié)點(diǎn)在邏輯上是不是同一對(duì)象。
3 .默認(rèn)行為性能上會(huì)有提升?建議盡可能在使用 v-for 時(shí)提供 key attribute,除非遍歷輸出的 DOM 內(nèi)容非常簡單,或者是刻意依賴默認(rèn)行為以獲取性能上的提升。官網(wǎng)文檔
4 .

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • MYSQL 基礎(chǔ)知識(shí) 1 MySQL數(shù)據(jù)庫概要 2 簡單MySQL環(huán)境 3 數(shù)據(jù)的存儲(chǔ)和獲取 4 MySQL基本操...
    Kingtester閱讀 8,059評(píng)論 5 115
  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴(yán)謹(jǐn) 對(duì)...
    cosWriter閱讀 11,644評(píng)論 1 32
  • 楊帛翰,1月份,第五次,讀書打卡。我讀的書名是:《西頓野生動(dòng)物,小說全集之,泡泡野豬。 西內(nèi)華達(dá)山脈坐落在...
    楊帛翰閱讀 558評(píng)論 0 0
  • 提高時(shí)間管理,一般來說有兩個(gè)方向。一是提高做事的效率,二是去做更有價(jià)值的事。時(shí)間管理=事件的價(jià)值×做事的效率。 工...
    討喜的魚閱讀 632評(píng)論 0 1

友情鏈接更多精彩內(nèi)容