Skip to content

值得您信賴的旅遊品牌 | 團體旅遊、自由行的專家‎

機場接送

Menu
  • 首頁
  • 旅遊天地
  • 裝潢設計
  • 環保清潔
  • 發燒車訊
Menu

Vue中key的作用

Posted on 2021-01-152021-01-15 by admin

Vue中key的作用

key的特殊attribute主要用在Vue的虛擬DOM算法,在新舊Nodes對比時辨識VNodes。如果不使用key,Vue會使用一種最大限度減少動態元素並且盡可能的嘗試就地修改、復用相同類型元素的算法,而使用key時,它會基於key的變化重新排列元素順序,並且會移除key不存在的元素。此外有相同父元素的子元素必須有獨特的key,重複的key會造成渲染錯誤。

描述

首先是官方文檔的描述,當Vue正在更新使用v-for渲染的元素列表時,它默認使用就地更新的策略,如果數據項的順序被改變,Vue將不會移動DOM元素來匹配數據項的順序,而是就地更新每個元素,並且確保它們在每個索引位置正確渲染。這個默認的模式是高效的,但是只適用於不依賴子組件狀態或臨時DOM狀態的列表渲染輸出,例如表單輸入值。為了給Vue一個提示,以便它能跟蹤每個節點的身份,從而重用和重新排序現有元素,你需要為每項提供一個唯一 key attribute,建議盡可能在使用v-for時提供key attribute,除非遍歷輸出的DOM內容非常簡單,或者是刻意依賴默認行為以獲取性能上的提升。
簡單來說,當在列表循環中使用key時,需要使用key來給每個節點做一個唯一標識,diff算法就可以正確的識別此節點,找到正確的位置直接操作節點,盡可能地進行重用元素,key的作用主要是為了高效的更新虛擬DOM。此外,使用index作為key是並不推薦的做法,其只能保證Vue在數據變化時強制更新組件,以避免原地復用帶來的副作用,但不能保證最大限度的元素重用,且使用index作為key在數據更新方面和不使用key的效果基本相同。

示例

首先定義一個Vue實例,渲染四個列表,分別為簡單列表與複雜列表,以及其分別攜帶key與不攜帶key時對比其更新渲染時的速度,本次測試使用的是Chrome 81.0,每次在Console執行代碼時首先會進行刷新重新加載界面,避免瀏覽器以及Vue自身優化帶來的影響。

<!DOCTYPE html>
<html>
<head>
    <title>Vue</title>
</head>
<body>
    <div id="app">
        <ul>
            <li v-for="item in simpleListWithoutKey" >{{item}}</li>
        </ul>

        <ul>
            <li v-for="item in simpleListWithKey" :key="item" >{{item}}</li>
        </ul>

        <ul>
            <li v-for="item in complexListWithoutKey">
                <span v-for="value in item.list" v-if="value > 5">{{value}}</span>
            </li>
        </ul>

        <ul>
            <li v-for="item in complexListWithKey" :key="item.id">
                <span v-for="value in item.list" :key="value" v-if="value > 5">{{value}}</span>
            </li>
        </ul>

    </div>
</body>
<script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js"></script>
<script type="text/javascript">
    var vm = new Vue({
        el: '#app',
        data: {
            simpleListWithoutKey: [1, 2, 3, 4, 5, 6],
            simpleListWithKey: [1, 2, 3, 4, 5, 6],
            complexListWithoutKey:[
                {id: 1, list: [1, 2, 3]},
                {id: 2, list: [4, 5, 6]},
                {id: 3, list: [7, 8, 9]}
            ],
            complexListWithKey:[
                {id: 1, list: [1, 2, 3]},
                {id: 2, list: [4, 5, 6]},
                {id: 3, list: [7, 8, 9]}
            ],
        }
    })
</script>
</html>

簡單列表

在簡單列表的情況下,不使用key可能會比使用key的情況下在更新時的渲染速度更快,這也就是官方文檔中提到的,除非遍歷輸出的DOM內容非常簡單,或者是刻意依賴默認行為以獲取性能上的提升。在下面的例子中可以看到沒有key的情況下列表更新時渲染速度會快,當不存在key的情況下,這個列表直接進行原地復用,原有的節點的位置不變,原地復用元素,將內容更新為5、6、7、8、9、10,並添加了11與12兩個節點,而存在key的情況下,原有的1、2、3、4節點被刪除,5、6節點保留,添加了7、8、9、10、11、12六個節點,由於在DOM的增刪操作上比較耗時,所以表現為不帶key的情況下速度更快一些。

// 沒有key的情況下
console.time();
vm.simpleListWithoutKey = [5, 6, 7, 8, 9, 10, 11, 12];
vm.$nextTick(() => console.timeEnd());
// default: 2.193056640625ms
// 存在key的情況下
console.time();
vm.simpleListWithKey = [5, 6, 7, 8, 9, 10, 11, 12];
vm.$nextTick(() => console.timeEnd());
// default: 3.2138671875ms

原地復用可能會帶來一些副作用,文檔中提到原地復用這個默認的模式是高效的,但是只適用於不依賴子組件狀態或臨時DOM狀態的列表渲染輸出,例如表單輸入值。在不設置key的情況下,元素中沒有與數據data綁定的部分,Vue會默認使用已經渲染的DOM,而綁定了數據data的部分會進行跟隨數據渲染,假如操作了元素位置,則元素中未綁定data的部分會停留在原地,而綁定了data的部分會跟隨操作進行移動,在下面的例子中首先需要將兩個A之後的輸入框添加數據信息,這樣就製作了一個臨時狀態,如果此時點擊下移按鈕,那麼不使用key的組中的輸入框將不會跟隨下移,且B到了頂端並成為了紅色,而使用key的組中會將輸入框進行下移,且A依舊是紅色跟隨下移。

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>就地復用</title>
</head>
<body>

  <div id="app">
    <h3>採用就地復用策略(vuejs默認情況)</h3>
    <div  v-for='(p, i) in persons'>
      <span>{{p.name}}<span>  
      <input type="text"/>  
      <button @click='down(i)' v-if='i != persons.length - 1'>下移</button>
    </div> 

    <h3>不採用就地復用策略(設置key)</h3>
    <div  v-for='(p, i) in persons' :key='p.id'>
      <span>{{p.name}}<span> 
      <input type="text"/>  
      <button @click='down(i)' v-if='i != persons.length - 1'>下移</button>
    </div>

  </div>
<script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js"></script>
  <script>
    new Vue({
      el: '#app',
      data: {
        persons: [
            { id: 1, name: 'A' },
            { id: 2, name: 'B' },
            { id: 3, name: 'C' }
        ]
      },
      mounted: function(){
        // 此DOM操作將兩個A的顏色設置為紅色 主要是為了演示原地復用
        document.querySelectorAll("h3 + div > span:first-child").forEach( v => v.style.color="red");
      },
      methods: {
        down: function(i) {
            if (i == this.persons.length - 1) return;
          var listClone = this.persons.slice();
          var one = listClone[i];
          listClone[i] = listClone[i + 1];
          listClone[i + 1] = one;
          this.persons = listClone;
        }
      }
    });
  </script>
</body>
</html>
<!-- 源於 https://www.zhihu.com/question/61078310 @霸都丶傲天 有修改-->

複雜列表

使用key不僅能夠避免上述的原地復用的副作用,且在一些操作上可能能夠提高渲染的效率,主要體現在重新排序的情況,包括在中間插入和刪除節點的操作,在下面的例子中沒有key的情況下重新排序會原地復用元素,但是由於v-if綁定了data所以會一併進行操作,在這個DOM操作上比較消耗時間,而使用key得情況則直接復用元素,v-if控制的元素在初次渲染就已經決定,在本例中沒有對其進行更新,所以不涉及v-if的DOM操作,所以在效率上會高一些。

console.time();
vm.complexListWithoutKey = [
        {id: 3, list: [7, 8, 9]},
        {id: 2, list: [4, 5, 6]},
        {id: 1, list: [1, 2, 3]},
    ];
vm.$nextTick(() => console.timeEnd());
vm.$nextTick(() => console.timeEnd());
// default: 4.100244140625ms
console.time();
vm.complexListWithKey = [
        {id: 3, list: [7, 8, 9]},
        {id: 2, list: [4, 5, 6]},
        {id: 1, list: [1, 2, 3]},
    ];
vm.$nextTick(() => console.timeEnd());
// default: 3.016064453125ms

每日一題

https://github.com/WindrunnerMax/EveryDay

參考

https://cn.vuejs.org/v2/api/#key
https://www.jianshu.com/p/4bdd2690859c
https://www.zhihu.com/question/61078310
https://segmentfault.com/a/1190000012861862
https://www.cnblogs.com/zhumingzhenhao/p/7688336.html
https://blog.csdn.net/hl18730262380/article/details/89306500
https://github.com/Advanced-Frontend/Daily-Interview-Question/issues/1
https://cn.vuejs.org/v2/guide/list.html#%E7%BB%B4%E6%8A%A4%E7%8A%B6%E6%80%81

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※網頁設計最專業,超強功能平台可客製化

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

※回頭車貨運收費標準

※推薦評價好的iphone維修中心

※教你寫出一流的銷售文案?

※台中搬家公司教你幾個打包小技巧,輕鬆整理裝箱!

※台中搬家公司費用怎麼算?

好站推薦

  • 健康醫療 減重知識專區
  • 婚紗世界 婚紗攝影寫真網
  • 成人話題 未滿18請勿進入
  • 流行時尚 時下流行愛美情報
  • 理財資訊 當舖借貸信用卡各式理財方法
  • 生活情報 各行各業情報資訊
  • 科技資訊 工業電子3C產品
  • 網路資訊 新奇趣味爆笑內容
  • 美食分享 全台各式名產 伴手禮
  • 裝潢設計 買屋賣屋裝修一羅框
  • 視覺設計 T恤、團體服、制服、polo衫

近期文章

  • 全球最大豬肉加工商因染疫關廠 警告肉類恐短缺
  • 奧運再生能源準備不延期 東京主場館的透明太陽能板 滋養草坪又能發電
  • 流氓鄰居!新研究:中國築壩攔水重創湄公河下游國水情
  • 美國人忙抗疫 川普悄悄對環境政策上下其手
  • 學者:野火致觀光客減少 有助控制澳洲疫情

標籤

USB CONNECTOR  南投搬家公司費用 古典家具推薦 台中一中住宿 台中一中民宿 台中室內設計 台中室內設計師 台中室內設計推薦 台中搬家 台中電動車 台北網頁設計 台東伴手禮 台東名產 地板施工 大圖輸出 如何寫文案 婚禮錄影 宜蘭民宿 家具工廠推薦 家具訂製工廠推薦 家具訂製推薦 實木地板 復刻家具推薦 新竹婚宴會館 木地板 木質地板 柚木地板 桃園機場接送 桃園自助婚紗 沙發修理 沙發換皮 海島型木地板 牛軋糖 租車 網站設計 網頁設計 網頁設計公司 貨運 超耐磨木地板 銷售文案 隱形鐵窗 電動車 馬賽克拼貼 馬賽克磁磚 馬賽克磚

彙整

  • 2021 年 3 月
  • 2021 年 2 月
  • 2021 年 1 月
  • 2020 年 12 月
  • 2020 年 11 月
  • 2020 年 10 月
  • 2020 年 9 月
  • 2020 年 8 月
  • 2020 年 7 月
  • 2020 年 6 月
  • 2020 年 5 月
  • 2020 年 4 月
  • 2020 年 3 月
  • 2020 年 2 月
  • 2020 年 1 月
  • 2019 年 12 月
  • 2019 年 11 月
  • 2019 年 10 月
  • 2019 年 9 月
  • 2019 年 8 月
  • 2019 年 7 月
  • 2019 年 6 月
  • 2019 年 5 月
  • 2019 年 4 月
  • 2019 年 3 月
  • 2019 年 2 月
  • 2019 年 1 月
  • 2018 年 12 月
©2021 值得您信賴的旅遊品牌 | 團體旅遊、自由行的專家‎ | Built using WordPress and Responsive Blogily theme by Superb