Heim >Web-Frontend >View.js >Eine eingehende Analyse der Schlüsselwerte in Vuejs
Dieser Artikel führt Sie in das relevante Wissen über die Schlüsselwerte in Vuejs ein. Es hat einen gewissen Referenzwert. Freunde in Not können sich darauf beziehen. Ich hoffe, es wird für alle hilfreich sein.
Vor ein paar Tagen habe ich einen Artikel geschrieben: sortable.js – Vue-Datenaktualisierungsproblem Damals habe ich ihn nur aus der Perspektive der erzwungenen Datenaktualisierung analysiert Der „Übeltäter“ wurde nicht gefunden.
Vielen Dank, dass mir jemand geholfen hat, darauf hinzuweisen, dass es möglicherweise der key
-Wert von Vue
ist, der dazu führt, dass die Daten falsch gerendert werden. Darauf aufbauend habe ich weitere Versuche unternommen. [Verwandte Empfehlungen: „vue.js-TutorialVue
的 key
值,导致数据渲染不正确的。由此,我做了进一步的尝试。【相关推荐:《vue.js教程》】
index
作为 key
不知道你在写 v-for
的时候,会不会直接使用 index
作为它的 key
值,是的,我承认我会,不得不说,这真的不是一个好习惯。
根据上篇文章,我们还是用 sortable.js
作为例子讨论。以下是核心代码,其中 arrData
的值为 [1,2,3,4]
<div id="sort"> <div v-for="(item,index) in arrData" :key="index" > <div>{{item}}</div> </div> </div>
mounted () { let el = document.getElementById('sort') var sortable = new Sortable(el, { onEnd: (e) => { const tempItem = this.arrData.splice(e.oldIndex, 1)[0] this.arrData.splice(e.newIndex, 0, tempItem) } }) }
当然一开始的时候,数据渲染肯定是没有问题的
好了,我们来看下以下的操作:
可以看到,我将3拖到2上面的时候,下面的数据变成了 1342,但是上面视图的还是1234。然后我第四位置拖到第三位置的时候,下面的数据也是生效的,但是上面的数据似乎全部错乱了。很好,我们重现了案发现场。
接着我改了绑定的 key
值,因为这里的例子比较特殊,我们就认为 item
的值都不相同
<div id="sort"> <div v-for="(item,index) in arrData" :key="item" > <div>{{item}}</div> </div> </div>
再看效果:
是的,这个时候数据就完全跟视图同步了。
为什么?
先看官方文档中 key
的一句介绍
有相同父元素的子元素必须有独特的 key。重复的 key 会造成渲染错误。
之所以会造成上面渲染错误的情况,是因为我们的 key
值不是独特的,比如上面的 key
值,在调整数组顺序后就每一项原来的 key
值都变了,所以导致了渲染错误。
我们先来得出一个结论,用 index
作为 key
值是有隐患的,除非你能保证 index
始终能够能够作为一个唯一的标识
在 vue2.0
之后,我们不写 key
的话,就会报 warning
,那也就是说官方是希望我们写 key
值的,那么 key
到底在 vue
中扮演了什么样的角色?
不使用 key 可以提高性能么答案是,是的!可以!
先看官方解释:
如果不使用 key,Vue 会使用一种最大限度减少动态元素并且尽可能的尝试修复/再利用相同类型元素的算法。使用 key,它会基于 key 的变化重新排列元素顺序,并且会移除 key 不存在的元素。
比如现在有一个数组 [1,2,3,4]变成了[2,1,3,4],那么没有 key
的值会采取一种“就地更新策略”,见下图。它不会移动元素节点的位置,而是直接修改元素本身,这样就节省了一部分性能
而对于有 key
值的元素,它的更新方式如下图所示。可以看到,这里它对 DOM 是移除/添加的操作,这是比较耗性能的。
竟然不带 key
性能更优,为何还要带 key先来看一个例子,核心代码如下,这里模仿一个切换 tab
"]
index
als Schlüssel
🎜🎜Ich wusste nicht, wann Sie v-for
geschrieben haben, ich Ich werde index
nicht direkt als seinen key
-Wert verwenden. Ja, ich muss zugeben, dass dies wirklich keine gute Vorgehensweise ist. 🎜🎜Basierend auf dem vorherigen Artikel verwenden wir immer noch sortable.js
als Beispiel für die Diskussion. Das Folgende ist der Kerncode, in dem der Wert von arrData
[1,2,3,4] ist img src="https ://img.php.cn/upload/image/332/990/370/1622613749680542.png" title="1622613749680542.png" alt="Eine eingehende Analyse der Schlüsselwerte in Vuejs"/>🎜🎜Okay, lass uns nehmen Schauen Sie sich die folgende Operation an: 🎜🎜🎜 🎜Sie können sehen, dass, wenn ich 3 über 2 ziehe, die Daten unten 1342 werden, die Ansicht oben jedoch immer noch 1234 ist. Als ich dann die vierte Position auf die dritte Position zog, wurden die Daten unten ebenfalls wirksam, aber die Daten oben schienen völlig durcheinander zu sein. Großartig, wir haben den Tatort nachgebildet. 🎜🎜Dann habe ich den gebundenen key
-Wert geändert. Da das Beispiel hier etwas ganz Besonderes ist, denken wir, dass die Werte von item
unterschiedlich sind.🎜<div id="sort"> <button @click="trunToTab1">tab1</button> <button @click="trunToTab2">tab2</button> <div v-for="(item, index) in arrData"> <div @click="clickItem(index)" class="item">{{item}}</div> </div> </div>🎜Sehen Sie sich den Effekt an nochmal:🎜 🎜🎜 🎜Ja, zu diesem Zeitpunkt sind die Daten vollständig mit der Ansicht synchronisiert. 🎜🎜Warum? 🎜🎜Lesen Sie zunächst die Einführung von
key
in der offiziellen Dokumentation.🎜🎜Untergeordnete Elemente mit demselben übergeordneten Element müssen einen eindeutigen Schlüssel haben. Doppelte Schlüssel führen zu Darstellungsfehlern. 🎜🎜Der obige Rendering-Fehler liegt daran, dass unser
key
-Wert nicht eindeutig ist. Beispielsweise wird der obige key
-Wert in der Array-Reihenfolge angepasst . Danach hat sich jeder ursprüngliche key
-Wert geändert, was zu Darstellungsfehlern geführt hat. 🎜🎜Lassen Sie uns zunächst eine Schlussfolgerung ziehen: Die Verwendung von index
als key
-Wert ist gefährlich, es sei denn, Sie können garantieren, dass index
dies immer kann als eindeutige Kennung verwendet werden🎜vue2.0
, wir Wenn Sie key
nicht schreiben, wird eine Warnung
gemeldet, was bedeutet, dass der Beamte möchte, dass wir den key
-Wert schreiben, dann key in <code>vue
? 🎜🎜Kann die Leistung ohne die Verwendung von Tasten verbessert werden?Die Antwort lautet: Ja! Dürfen! 🎜🎜Schauen Sie sich zuerst die offizielle Erklärung an: 🎜🎜Wenn der Schlüssel nicht verwendet wird, verwendet Vue einen Algorithmus, der dynamische Elemente minimiert und versucht, Elemente desselben Typs so weit wie möglich zu reparieren/wiederzuverwenden. Mithilfe von „key“ wird die Reihenfolge der Elemente basierend auf Schlüsseländerungen neu angeordnet und Elemente entfernt, bei denen „key“ nicht vorhanden ist. 🎜🎜Wenn beispielsweise ein Array [1,2,3,4] zu [2,1,3,4] wird, dann hat der Wert ohne
key
die Form „ In-Place-Update-Strategie“, siehe Abbildung unten. Es verschiebt nicht die Position des Elementknotens, sondern ändert direkt das Element selbst und spart so etwas Leistung🎜🎜🎜🎜Für Elemente mit key
-Werten ist die Aktualisierungsmethode wie in der folgenden Abbildung dargestellt. Wie Sie sehen, handelt es sich hier um einen Vorgang zum Entfernen/Hinzufügen zum DOM, der relativ leistungsintensiv ist. 🎜🎜🎜🎜Ohne key
ist die Leistung besser. Schauen wir uns zunächst ein Beispiel an. Hier imitieren wir die Funktion des tab
, das heißt, der umgeschaltete tab1 ist 1,2,3,4. tab2 ist 5,6,7,8. Es gibt eine Funktion, um die Schriftfarbe des ersten Elements durch Anklicken auf Rot zu setzen. 🎜那么当我们点击tab1将字体色设置成红色之后,再切换到 tab2,我们预期的结果是我们第一项字体的初始颜色而不是红色,但是结果却还是红色。
<div id="sort"> <button @click="trunToTab1">tab1</button> <button @click="trunToTab2">tab2</button> <div v-for="(item, index) in arrData"> <div @click="clickItem(index)" class="item">{{item}}</div> </div> </div>
trunToTab1 () { this.arrData = [1,2,3,4] }, trunToTab2 () { this.arrData = [5,6,7,8] }, clickItem () { document.getElementsByClassName('item')[0].style.color = 'red' }
这就超出了我们的预期了,也就是官方文档所说的,默认模式指的就是不带 key
的状态,对于依赖于子组件状态或者临时 DOM 状态的,这种模式是不适用的。
这个默认的模式是高效的,但是只适用于不依赖子组件状态或临时 DOM 状态 (例如:表单输入值) 的列表渲染输出。
我们来看带上 key
之后的效果
这就是官方文档之所以推荐我们写 key
的原因,根据文档的介绍,如下:
使用
key
,它会基于key
的变化重新排列元素顺序,并且会移除key
不存在的元素。 它也可以用于强制替换元素/组件而不是重复使用它。当你遇到如下场景的时候它可能会很有用:
- 完整地触发组件的生命周期钩子
- 触发过渡
那么 Vue
底层 key
值到底是怎么去做到以上的功能?我们就得聊聊 diff
算法以及虚拟 DOM
了。
这里我们不谈 diff
算法的具体,只看 key
值在其中的作用。(diff
算法有机会我们再聊)
看 vue
源码中 src/core/vdom/patch.js
if (isUndef(oldKeyToIdx)) oldKeyToIdx = createKeyToOldIdx(oldCh, oldStartIdx, oldEndIdx) idxInOld = isDef(newStartVnode.key) ? oldKeyToIdx[newStartVnode.key] : findIdxInOld(newStartVnode, oldCh, oldStartIdx, oldEndIdx)
我们整理一下代码块:
// 如果有带 key if (isUndef(oldKeyToIdx)) { // 创建 index 表 oldKeyToIdx = createKeyToOldIdx(oldCh, oldStartIdx, oldEndIdx); } if (isDef(newStartVnode.key)) { // 有 key ,直接从上面创建中获取 idxInOld = oldKeyToIdx[newStartVnode.key] } else { // 没有key, 调用 findIdxInOld idxInOld = findIdxInOld(newStartVnode, oldCh, oldStartIdx, oldEndIdx); }
那么最主要还是 createKeyToOldIdx
和 findIdxInOld
两个函数的比较,那么他们做了什么呢?
function createKeyToOldIdx (children, beginIdx, endIdx) { let i, key const map = {} for (i = beginIdx; i <= endIdx; ++i) { key = children[i].key if (isDef(key)) map[key] = i } return map }
function findIdxInOld (node, oldCh, start, end) { for (let i = start; i < end; i++) { const c = oldCh[i] if (isDef(c) && sameVnode(node, c)) return i } }
我们可以看到,如果我们有 key
值,我们就可以直接在 createKeyToOldIdx
方法中创建的 map
对象中根据我们的 key
值,直接找到相应的值。没有 key
值,则需要遍历才能拿到。相比于遍历,映射的速度会更快。
key
值是每一个 vnode
的唯一标识,依靠 key
,我们可以更快的拿到 oldVnode
中相对应的节点。
更多编程相关知识,请访问:编程视频!!
Das obige ist der detaillierte Inhalt vonEine eingehende Analyse der Schlüsselwerte in Vuejs. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!