热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

v3+ts慢慢学习之路四【vfor和它当中的key】

“会倾听”比“会表达”更为难得一、v-for支持的类型1、遍历数组v-for遍历数组一:“itemin数组”v-for遍历数组二:“(item,in

“会倾听” 比 “会表达”更为难得


一、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的情况下

// 未使用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_ARR// 1、旧节点长度const oldLength &#61; c1.length// 2、新节点长度const newLength &#61; c2.length// 3、获取新旧节点最小的长度const commonLength &#61; Math.min(oldLength, newLength)let i// 4、从0的位置开始依次patch比较for (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)}// 5、如果旧节点长度依旧大于新节点长度&#xff0c;那么就移除旧节点if (oldLength > newLength) {// remove oldunmountChildren(c1, parentComponent, parentSuspense, true, commonLength)} else {// 6、否则就创建新节点// mount newmountChildren(c2,container,anchor,parentComponent,parentSuspense,isSVG,optimized,commonLength)}}

未使用KEY的过程如下图

在这里插入图片描述

使用KEY的情况下

// 在使用KEY的情况下
// can be all-keyed or mixedconst 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 // prev ending indexlet e2 &#61; l2 - 1 // next ending index// 1、从头部开始遍历&#xff0c;遇到相同节点就继续&#xff0c;遇到不同的就跳出循环// 1. sync from start// (a b) c// (a b) d ewhile (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;}// 2、从尾部开始遍历&#xff0c;遇到相同节点就继续&#xff0c;遇到不同就跳出循环// 2. sync from end// a (b c)// d e (b c)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--}// 3、如果旧节点遍历完了&#xff0c;依然有新的节点&#xff0c;那么新的节点就是添加// 3. common sequence &#43; mount// (a b)// (a b) c// i &#61; 2, e1 &#61; 1, e2 &#61; 2// (a b)// c (a b)// i &#61; 0, e1 &#61; -1, e2 &#61; 0if (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;}}}// 4、如果新节点遍历完了&#xff0c;还有旧的节点&#xff0c;那么旧节点就是移除的// 4. common sequence &#43; unmount// (a b) c// (a b)// i &#61; 2, e1 &#61; 2, e2 &#61; 1// a (b c)// (b c)// i &#61; 0, e1 &#61; 0, e2 &#61; -1else if (i > e2) {while (i <&#61; e1) {unmount(c1[i], parentComponent, parentSuspense, true)i&#43;&#43;}}// 5、如果中间存在不知道如何排列的位置序列&#xff0c;那么就是用key建立索引图最大限度的使用旧节点// 5. unknown sequence// [i ... e1 &#43; 1]: a b [c d e] f g// [i ... e2 &#43; 1]: a b [e d c h] f g// i &#61; 2, e1 &#61; 4, e2 &#61; 5else {const s1 &#61; i // prev starting indexconst s2 &#61; i // next starting index// 5.1 build key:index map for newChildrenconst 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)}}// 5.2 loop through old children left to be patched and try to patch// matching nodes & remove nodes that are no longer presentlet jlet patched &#61; 0const toBePatched &#61; e2 - s2 &#43; 1let moved &#61; false// used to track whether any node has movedlet maxNewIndexSoFar &#61; 0// works as Map// Note that oldIndex is offset by &#43;1// and oldIndex &#61; 0 is a special value indicating the new node has// no corresponding old node.// used for determining longest stable subsequenceconst 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) {// all new children have been patched so this can only be a removalunmount(prevChild, parentComponent, parentSuspense, true)continue}let newIndexif (prevChild.key !&#61; null) {newIndex &#61; keyToNewIndexMap.get(prevChild.key)} else {// key-less node, try to locate a key-less node of the same typefor (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;}}// 5.3 move and mount// generate longest stable subsequence only when nodes have movedconst increasingNewIndexSequence &#61; moved? getSequence(newIndexToOldIndexMap): EMPTY_ARRj &#61; increasingNewIndexSequence.length - 1// looping backwards so that we can use last patched node as anchorfor (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) {// mount newpatch(null,nextChild,container,anchor,parentComponent,parentSuspense,isSVG)} else if (moved) {// move if:// There is no stable subsequence (e.g. a reverse)// OR current node is not among the stable sequenceif (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算法更加的高效


推荐阅读
  • Ihavetwomethodsofgeneratingmdistinctrandomnumbersintherange[0..n-1]我有两种方法在范围[0.n-1]中生 ... [详细]
  • 在尝试对从复杂 XSD 生成的类进行序列化时,遇到了 `NullReferenceException` 错误。尽管已经花费了数小时进行调试和搜索相关资料,但仍然无法找到问题的根源。希望社区能够提供一些指导和建议,帮助解决这一难题。 ... [详细]
  • 题目描述:牛客网新员工Fish每天早上都会拿着一本英文杂志,在本子上写下一些句子。他的同事Cat对这些句子非常感兴趣,但发现这些句子的单词顺序被反转了。例如,“student. a am I”实际上是“I am a student.”。Cat请求你帮助他恢复这些句子的正常顺序。 ... [详细]
  • 在处理大规模数据数组时,优化分页组件对于提高页面加载速度和用户体验至关重要。本文探讨了如何通过高效的分页策略,减少数据渲染的负担,提升应用性能。具体方法包括懒加载、虚拟滚动和数据预取等技术,这些技术能够显著降低内存占用和提升响应速度。通过实际案例分析,展示了这些优化措施的有效性和可行性。 ... [详细]
  • 在 CentOS 7 系统中安装 Scrapy 时遇到了一些挑战。尽管 Scrapy 在 Ubuntu 上安装简便,但在 CentOS 7 上需要额外的配置和步骤。本文总结了常见问题及其解决方案,帮助用户顺利安装并使用 Scrapy 进行网络爬虫开发。 ... [详细]
  • POJ 2482 星空中的星星:利用线段树与扫描线算法解决
    在《POJ 2482 星空中的星星》问题中,通过运用线段树和扫描线算法,可以高效地解决星星在窗口内的计数问题。该方法不仅能够快速处理大规模数据,还能确保时间复杂度的最优性,适用于各种复杂的星空模拟场景。 ... [详细]
  • Vue CLI 初始化 Webpack 项目时,main.js 文件是如何被调用的? ... [详细]
  • 如何使用ES6语法编写Webpack配置文件? ... [详细]
  • TypeScript ESLint: 避免使用隐式 any 类型,建议指定更具体的类型以提高代码可维护性
    在使用 Vue 引入 SVGSpriteLoader 时遇到了问题。具体表现为在 `shims-vue.d.ts` 文件中进行相关配置后,WebStorm 报错。为了解决这一问题,建议避免使用隐式 `any` 类型,而是指定更具体的类型,以提高代码的可维护性和类型安全性。可以通过在 ESLint 配置中禁用隐式 `any` 类型来实现这一目标。 ... [详细]
  • Vue应用预渲染技术详解与实践 ... [详细]
  • 尽管我们尽最大努力,任何软件开发过程中都难免会出现缺陷。为了更有效地提升对支持部门的协助与支撑,本文探讨了多种策略和最佳实践,旨在通过改进沟通、增强培训和支持流程来减少这些缺陷的影响,并提高整体服务质量和客户满意度。 ... [详细]
  • 在 Vue 中,可以通过 `ref` 属性精确控制滚动条的位置。具体来说,使用 `ref` 获取 DOM 元素,并通过事件处理函数(如点击事件)来调整滚动条的滚动距离。需要注意的是,直接使用 `$refs` 可能不会立即生效,因此需要确保在适当的生命周期钩子或异步操作中进行操作。此外,结合 `nextTick` 方法可以确保 DOM 更新完成后再执行滚动操作,从而实现更稳定的控制效果。 ... [详细]
  • 在 Vue 3 项目中使用 ElementPlus 的 Icon 组件时,遇到了 SVG 图标无法正常显示的问题。经过查阅官方文档和 GitHub 讨论,最终发现是由于图标路径配置不正确导致的。通过调整图标路径和引入方式,成功解决了这一问题,并确保了图标能够正确加载和显示。此外,还对项目依赖进行了更新,以兼容最新的 ElementPlus 版本。 ... [详细]
  • 深入解析Gradle中的Project核心组件
    在Gradle构建系统中,`Project` 是一个核心组件,扮演着至关重要的角色。通过使用 `./gradlew projects` 命令,可以清晰地列出当前项目结构中包含的所有子项目,这有助于开发者更好地理解和管理复杂的多模块项目。此外,`Project` 对象还提供了丰富的配置选项和生命周期管理功能,使得构建过程更加灵活高效。 ... [详细]
  • 在Vite项目优化过程中,通过使用rollup-plugin-visualizer插件,可以有效地对Rollup打包结果进行可视化分析,帮助开发者清晰地了解各个模块的占用情况,从而进行更有针对性的优化。此外,结合其他常用插件,如vite-plugin-compression和vite-plugin-inspect,可以进一步提升项目的性能和可维护性。 ... [详细]
author-avatar
青岛淘宝摄影
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有