“会倾听” 比 “会表达”更为难得
一、v-for支持的类型
1、遍历数组
- v-for遍历数组一: “item in 数组”
- v-for遍历数组二 :“(item,index) in 数组”
2、遍历对象
- v-for遍历对象一: “value in 对象”
- v-for遍历对象二:“(value,key) in 对象”
- v-for遍历对象三:“(value,key,index) in 对象”
3、遍历数字
- v-for遍历对数字: “item in 数字”
- 每一个item都是一个数字
二、 v-for中的key是什么作用
先看一段官方对v-for的介绍
简单翻译总结:
1、 key主要用于Vue的虚拟DOM算法,在新旧nodes对比时辨别VNodes;
2、不使用key,Vue会使用一种算法尽可能的尝试就地修改/复用相同类型元素;
3、使用key时,它会基于key的变化重新排列元素顺序,并且会移除/销毁key不存在的元素;
遇事不决,就先看看源码,Vue到是怎么区分
源码中是如何区分有key和没有key的
未使用KEY的情况下
const patchUnkeyedChildren &#61; (c1: VNode[],c2: VNodeArrayChildren,container: RendererElement,anchor: RendererNode | null,parentComponent: ComponentInternalInstance | null,parentSuspense: SuspenseBoundary | null,isSVG: boolean,optimized: boolean) &#61;> {c1 &#61; c1 || EMPTY_ARRc2 &#61; c2 || EMPTY_ARRconst oldLength &#61; c1.lengthconst newLength &#61; c2.lengthconst commonLength &#61; Math.min(oldLength, newLength)let ifor (i &#61; 0; i < commonLength; i&#43;&#43;) {const nextChild &#61; (c2[i] &#61; optimized? cloneIfMounted(c2[i] as VNode): normalizeVNode(c2[i]))patch(c1[i],nextChild,container,null,parentComponent,parentSuspense,isSVG,optimized)}if (oldLength > newLength) {unmountChildren(c1, parentComponent, parentSuspense, true, commonLength)} else {mountChildren(c2,container,anchor,parentComponent,parentSuspense,isSVG,optimized,commonLength)}}
未使用KEY的过程如下图
使用KEY的情况下
const patchKeyedChildren &#61; (c1: VNode[],c2: VNodeArrayChildren,container: RendererElement,parentAnchor: RendererNode | null,parentComponent: ComponentInternalInstance | null,parentSuspense: SuspenseBoundary | null,isSVG: boolean,optimized: boolean) &#61;> {let i &#61; 0const l2 &#61; c2.lengthlet e1 &#61; c1.length - 1 let e2 &#61; l2 - 1 while (i <&#61; e1 && i <&#61; e2) {const n1 &#61; c1[i]const n2 &#61; (c2[i] &#61; optimized? cloneIfMounted(c2[i] as VNode): normalizeVNode(c2[i]))if (isSameVNodeType(n1, n2)) {patch(n1,n2,container,null,parentComponent,parentSuspense,isSVG,optimized)} else {break}i&#43;&#43;}while (i <&#61; e1 && i <&#61; e2) {const n1 &#61; c1[e1]const n2 &#61; (c2[e2] &#61; optimized? cloneIfMounted(c2[e2] as VNode): normalizeVNode(c2[e2]))if (isSameVNodeType(n1, n2)) {patch(n1,n2,container,null,parentComponent,parentSuspense,isSVG,optimized)} else {break}e1--e2--}if (i > e1) {if (i <&#61; e2) {const nextPos &#61; e2 &#43; 1const anchor &#61; nextPos < l2 ? (c2[nextPos] as VNode).el : parentAnchorwhile (i <&#61; e2) {patch(null,(c2[i] &#61; optimized? cloneIfMounted(c2[i] as VNode): normalizeVNode(c2[i])),container,anchor,parentComponent,parentSuspense,isSVG)i&#43;&#43;}}}else if (i > e2) {while (i <&#61; e1) {unmount(c1[i], parentComponent, parentSuspense, true)i&#43;&#43;}}else {const s1 &#61; i const s2 &#61; i const keyToNewIndexMap: Map<string | number, number> &#61; new Map()for (i &#61; s2; i <&#61; e2; i&#43;&#43;) {const nextChild &#61; (c2[i] &#61; optimized? cloneIfMounted(c2[i] as VNode): normalizeVNode(c2[i]))if (nextChild.key !&#61; null) {if (__DEV__ && keyToNewIndexMap.has(nextChild.key)) {warn(&#96;Duplicate keys found during update:&#96;,JSON.stringify(nextChild.key),&#96;Make sure keys are unique.&#96;)}keyToNewIndexMap.set(nextChild.key, i)}}let jlet patched &#61; 0const toBePatched &#61; e2 - s2 &#43; 1let moved &#61; falselet maxNewIndexSoFar &#61; 0const newIndexToOldIndexMap &#61; new Array(toBePatched)for (i &#61; 0; i < toBePatched; i&#43;&#43;) newIndexToOldIndexMap[i] &#61; 0for (i &#61; s1; i <&#61; e1; i&#43;&#43;) {const prevChild &#61; c1[i]if (patched >&#61; toBePatched) {unmount(prevChild, parentComponent, parentSuspense, true)continue}let newIndexif (prevChild.key !&#61; null) {newIndex &#61; keyToNewIndexMap.get(prevChild.key)} else {for (j &#61; s2; j <&#61; e2; j&#43;&#43;) {if (newIndexToOldIndexMap[j - s2] &#61;&#61;&#61; 0 &&isSameVNodeType(prevChild, c2[j] as VNode)) {newIndex &#61; jbreak}}}if (newIndex &#61;&#61;&#61; undefined) {unmount(prevChild, parentComponent, parentSuspense, true)} else {newIndexToOldIndexMap[newIndex - s2] &#61; i &#43; 1if (newIndex >&#61; maxNewIndexSoFar) {maxNewIndexSoFar &#61; newIndex} else {moved &#61; true}patch(prevChild,c2[newIndex] as VNode,container,null,parentComponent,parentSuspense,isSVG,optimized)patched&#43;&#43;}}const increasingNewIndexSequence &#61; moved? getSequence(newIndexToOldIndexMap): EMPTY_ARRj &#61; increasingNewIndexSequence.length - 1for (i &#61; toBePatched - 1; i >&#61; 0; i--) {const nextIndex &#61; s2 &#43; iconst nextChild &#61; c2[nextIndex] as VNodeconst anchor &#61;nextIndex &#43; 1 < l2 ? (c2[nextIndex &#43; 1] as VNode).el : parentAnchorif (newIndexToOldIndexMap[i] &#61;&#61;&#61; 0) {patch(null,nextChild,container,anchor,parentComponent,parentSuspense,isSVG)} else if (moved) {if (j < 0 || i !&#61;&#61; increasingNewIndexSequence[j]) {move(nextChild, container, anchor, MoveType.REORDER)} else {j--}}}}}
使用KEY的过程如下图
总结&#xff1a;Vue在进行diff算法的时候&#xff0c;会尽量利用我们的key来进行优化操作
1、在没有key的时候我们的效率是非常低效的
2、在进行插入或者重置顺序的时候&#xff0c;保持相同的key可以让diff算法更加的高效