vue中的key

前言

題目來源:juejin.im/post/5d23e7…html

目標:經過面試題來讓本身的知識面更加廣,更加深刻。vue

(滴滴、餓了麼)寫 React / Vue 項目時爲何要在列表組件中寫 key,其做用是什麼?

key關鍵詞是什麼

首先咱們從官網的解釋出發:node

劃重點面試

  • key會用在虛擬DOM算法(diff算法)中,用來辨別新舊節點。
  • 不帶key的時候會最大限度減小元素的變更,儘量用相同元素。(就地複用)
  • 帶key的時候,會基於相同的key來進行排列。(相同的複用)
  • 帶key還能觸發過渡效果,以及觸發組件的生命週期

上面這麼4點就是官方文檔中主要解釋的意思。吃透了以上幾點,也就知道了key是什麼以及他的做用。算法

從源碼層面來窺探key在diff算法中的做用

  • 判斷是不是相同節點的時候

diff算法咱們知道,他會判斷開始和結尾4個節點是不是相同的節點,而這個sameVnode第一步就是判斷兩個元素的key值。意味着key相同,它們纔有多是相同元素,不相同,直接返回false。api

  • 判斷是不是相同的靜態節點的時候

判斷靜態節點也是和上述流程一致的。

  • 建立key-index的map的時候

這邊我只是截取了代碼片斷,這一步是將vnode的子元素數組,生成key-index的map,方便經過key去查找對應的index子元素,進行相同節點的比較。而它的上文是先後4個新舊節點兩兩對比不成功的狀況下,下文就是經過這個map去定位相同的元素。數組

帶key和不帶key,誰的速度更快

聊到速度這個話題,咱們先能夠從本質上比較一下。bash

咱們用簡單的數據渲染的例子來看一下app

  • 不帶key的時候

實例代碼以下:dom

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <div id="app">
        <div @click="changeData">切換數據</div>
        <li v-for="item in list">{{ item.text }}</li>     
    </div>
    <script src="../../dist/vue.min.js"></script>
    <script type="module" crossorigin=「use-credentials」>
        var app = new Vue({
            el: '#app',
            data: {
                list: [],
                list1: [],
                list2: [],
                nowDate: '',
                updateTime: '',
            },
            created() {
                for (let i = 0; i <= 100000; i++) {
                    this.list1.push({
                        id: i,
                        text: i
                    })
                    this.list2.push({
                        id: i * 2,
                        text: 100000 - i
                    })
                }
                this.list = this.list1
            },
            methods: {
                changeData() {
                    this.nowDate = Date.now();
                    this.list = this.list2;
                }
            },
            updated() {
                const date = Date.now();
                console.log(`updateTime: ${date - this.nowDate}`);
            }
        })
    </script>
</body>
</html>
複製代碼

  • 帶key的時候

將上述遍歷的html代碼帶上key值。

<li v-for="item in list" :key="item.id">{{ item.text }}</li>     
複製代碼

總結: 不帶key的速度是更快的。緣由有以下:在上述例子中,不帶key的省略了銷燬和建立dom的開銷,只須要替換文本節點就ok了,而帶key的卻須要進行patch流程,並且須要把能複用的那部分元素找出來,將不能複用的消除,而且從新建立新的dom元素。

不帶key會有什麼弊病

既然咱們從上面檢測出來,是不帶key的會更快一點,那麼咱們爲何要帶key呢?

一、不帶key自己來講沒問題,可是當你遍歷的元素中,有組件的時候,就會發現問題。由於組件是能夠帶有自身狀態的。咱們來看一下下面這個例子:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <div id="app">
        <div  v-for="(item, index) in list">
            <component-a></component-a>     
            <button @click="deleteInput(index)">刪除</button>
        </div>
    </div>
    <script src="../../dist/vue.min.js"></script>
    <script type="module" crossorigin=「use-credentials」>
        var ComponentA = {
            data: function () {
                return {
                    input: 0
                }
            },
            template: '<input v-model="input" />'
        }
        var app = new Vue({
            el: '#app',
            data: {
                list: ['1', '2', '3'],
            },
            methods: {
                changeData() {
                    this.nowDate = Date.now();
                    this.list = this.list2;
                },
                deleteInput(index) {
                    this.list.splice(index, 1);
                }
            },
            components: {
                ComponentA
            }
        })
    </script>
</body>
</html>
複製代碼

上述代碼很簡單,主要實現一下功能:

一、組件攜帶有本身狀態的input
二、頁面遍歷子組件生成3個input
複製代碼

而後點擊中間那個刪除,生成的結果:

指望的結果:

你們能夠綁key以後試一下,就是咱們指望的結果。

二、帶key的由於不是就地複用,因此能夠實現一些過渡的動畫效果。

建議不要用index值去做爲key的值

平時咱們很喜歡用index去做爲key的索引,可是這樣的話,key值就失去了自己的意義,在遇到上述那幾個例子的時候,一樣回去踩坑。

不少集團項目中,會用到eslint去檢測template中v-for是否用了key值。從而減小錯誤率。那麼key最好和數據返回的id值去綁定。

總結

這個知識點其實很淺,可是也改變了個人不少認知。

一、不必定不少時候都要寫key值,若是是簡單的列表渲染,我以爲大可沒必要。

二、當你要去寫key值的時候,最好不要用index,由於index這個值和就地複用沒啥區別。

三、當你要實現一些過渡效果的時候,不妨看一下vue的文檔,有一些現成的過渡效果能夠直接用。

相關文章
相關標籤/搜索