Why to add attribute key in Vue v-for

It is highly recommended to add the key attribute when using v-for on the Vue official website. This article looks at the difference between adding attribute key and not adding attribute key. Let's simulate the processing flow of this part in Vue. First, create 3 div elements. The content is

xiaozhang

xiaowang

xiaoliu

Then add a new div element xiaoli before the first div element. The rendered content is as follows:

xiaoli

xiaozhang

xiaowang

xiaoliu

We use an object array to simulate this process. The object array is as follows:

        //Bring key data
        var oldList = [{ key : 10, name : "xiaozhang", tag : "div"},
                       { key : 11, name : "xiaowang", tag : "div"},
                       { key : 12, name : "xiaoliu", tag : "div"}]

        var newList = [{ key : 9,  name : "xiaoli", tag : "div"},
                       { key : 10, name : "xiaozhang", tag : "div"},
                       { key : 11, name : "xiaowang", tag : "div"},
                       { key : 12, name : "xiaoliu", tag : "div"}]
        //Without key data
        var oldList_ = [{ name : "xiaozhang", tag : "div"},
                       { name : "xiaowang", tag : "div"},
                       { name : "xiaoliu", tag : "div"}]

        var newList_ = [{ name : "xiaoli", tag : "div"},
                       { name : "xiaozhang", tag : "div"},
                       { name : "xiaowang", tag : "div"},
                       { name : "xiaoliu", tag : "div"}]

In the data with key, the object has the key attribute. When v-for is used in simulation, the object has the key attribute (: key="item.key").

First, we use oldList to create three div elements and insert them into the parent node. Then we use newList to update the three div elements and insert the new element "xiaoli". The code is as follows:

<html>

<head>
    <style type="text/css">

    </style>
</head>

<body>


    <div id="app">

    </div>
    <script>

        //Bring key data
        var oldList = [{ key : 10, name : "xiaozhang", tag : "div"},
                       { key : 11, name : "xiaowang", tag : "div"},
                       { key : 12, name : "xiaoliu", tag : "div"}]

        var newList = [{ key : 9,  name : "xiaoli", tag : "div"},
                       { key : 10, name : "xiaozhang", tag : "div"},
                       { key : 11, name : "xiaowang", tag : "div"},
                       { key : 12, name : "xiaoliu", tag : "div"}]
        //Without key data
        var oldList_ = [{ name : "xiaozhang", tag : "div"},
                       { name : "xiaowang", tag : "div"},
                       { name : "xiaoliu", tag : "div"}]

        var newList_ = [{ name : "xiaoli", tag : "div"},
                       { name : "xiaozhang", tag : "div"},
                       { name : "xiaowang", tag : "div"},
                       { name : "xiaoliu", tag : "div"}]

        //First create 3 div elements
        function createDom(parentElm, list){
            var dom3 = document.createElement(list[2].tag);
            dom3.textContent = list[2].name;
            parentElm.appendChild(dom3);

            var dom2 = document.createElement(list[1].tag);
            dom2.textContent = list[1].name;
            parentElm.insertBefore(dom2, dom3);

            var dom1 = document.createElement(list[0].tag);
            dom1.textContent = list[0].name;
            parentElm.insertBefore(dom1, dom2);
        }
 
        // createDom(document.getElementById("app"), oldList "; / / without key
         createDom(document.getElementById("app"), oldList);  //Tape key

        function isSameVNode(oldNode, newNode){
            //Judge whether the new and old nodes are the same according to the key
            return (oldNode.key === newNode.key) && (oldNode.tag === newNode.tag);
        }

        //Update node
        function updateDom(parentElm, oldList, newList){
            var oldStartIdx = 0, newStartIdx = 0;
            var oldEndIdx = oldList.length - 1, newEndIdx = newList.length - 1;
            var oldStartVNode = oldList[0], newStartVNode = newList[0];
            var oldEndVNode = oldList[oldEndIdx], newEndVNode = newList[newEndIdx];

            while (oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx){
                if(isSameVNode(oldStartVNode, newStartVNode)){
                    //Start from the beginning of the new and old node list, and take this branch for nodes without key. Because there is no key, all keys are undefined
                    if(oldStartVNode.name !== newStartVNode.name){
                        console.log("update dom"); //The content of the old and new nodes is different. Update the content in the dom
                        parentElm.children[newStartIdx].textContent = newStartVNode.name;
                    }
                    oldStartVNode = oldList[++oldStartIdx];
                    newStartVNode = newList[++newStartIdx];
                }else if(isSameVNode(oldEndVNode, newEndVNode)){
                    //Start from the end of the list of new and old nodes, and take this branch for nodes with key
                    if(oldEndVNode.name !== newEndVNode.name){
                        //When traversing from the end, the contents of the first three DOM elements are the same, so we will not go here, nor operate the dom,
                        parentElm.children[newEndIdx].textContent = newEndVNode.name;
                    }
                    oldEndVNode = oldList[--oldEndIdx];
                    newEndVNode = newList[--newEndIdx];
                }
            }
    
            if (oldStartIdx > oldEndIdx) {
                //After traversing, there are more new nodes than old ones, so you need to add more nodes
                if(newList[newEndIdx + 1] !== undefined){
                    //Take this branch with key and insert an element "xiaoli" in front of the three child nodes
                    var dom0 = document.createElement(newList[0].tag);
                    dom0.textContent = newList[0].name;
                    parentElm.insertBefore(dom0, parentElm.children[newEndIdx]);
                }else{
                    //Take this branch without key, and insert an element "xiaoliu" at the end of the three child nodes“
                    var dom3 = document.createElement(newList[newEndIdx].tag);
                    dom3.textContent = newList[newEndIdx].name;
                    parentElm.appendChild(dom3);
                }
            }
        }

        setTimeout(() => {
            //Update dom
            // Updatedom (document. Getelementbyid ("app"), oldlist, NEWLIST); / / without key
             updateDom(document.getElementById("app"), oldList, newList); //Tape key
        }, 2000);
    </script>

</body>

</html>

We have made detailed comments in the code. If there is something unclear, you can debug it step by step.

When you have a key, you start to traverse from the last element of the object array. Because the content of the element textContent is the same, you don't need to operate the dom, reuse the previous dom elements, do nothing, and traverse the next element. Finally, insert the newly added element at the front. As shown in the figure below:

When there is no key, we start to traverse from the first element of the object array. Because the first element of the old object array is different from the first element of the new object array, to operate the DOM, change the textContent to "xiaoli". The second element of the new and old array, which is the same as the third element, needs to operate the dom. Finally, we also need to operate the dom To insert the fourth element, xiaoliu. As shown in the figure below:

 

Published 178 original articles, won praise 13, visited 100000+
Private letter follow

Keywords: Attribute Vue

Added by phpPete on Sat, 08 Feb 2020 13:28:58 +0200