Vue系列之(二)——Vue中的v-for到底做了什么?

循环使用 v-for 指令。

先来了解一下v-for的原理,话不多说,先看代码~
完整代码:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>02v-for</title>
</head>

<body>
    <div id='app'>
        <prolist></prolist>
    </div>
</body>
<template id="prolist">
    <ul>
        <li v-for="item in list" :key="item.id">
            {{item.name}}
        </li>
    </ul>
</template>
<script src="vue.js"></script>
<script>
    const ProList = {
        template: '#prolist',
        data() {
            return {
                list: [
                    { id: 1, name: '李斯' },
                    { id: 2, name: '嬴政' },
                    { id: 3, name: '赵高' },
                    { id: 4, name: '韩非' },
                    { id: 5, name: '荀子' },
                ]
            }
        },
    }
    new Vue({
        el: '#app',
        data: {},
        components: {
            prolist: ProList
        }
    })
</script>

</html>

在vue里面,我们通过v-for指令来渲染一个数组列表,即:

	<ul>
        <li v-for="item in list">
            {{item.name}}
        </li>
    </ul>

上面这个例子中,list 是我们要渲染的数组列表,item是数组列表项的别名,当然,我们也可以给v-for添加第二个参数作为当前项的索引,如下:

	<ul>
        <li v-for="(item,index) in list">
            {{ index }} --- {{ item.name }}
        </li>
    </ul>

我们可以发现,上面的两个例子都少了一个属性:key,确实是这样子的,官方文档强烈建议我们给v-for渲染的每一个列表项指定一个key,key的作用是什么呢?官方文档给出的解释如下:

Vue系列之(二)——Vue中的v-for到底做了什么?_第1张图片

v-for中的key值

v-for 指令需要以 site in sites 形式的特殊语法, sites 是源数据数组并且 site 是数组元素迭代的别名。v-for 可以绑定数据到数组来渲染一个列表、数组

当Vue用 v-for 正在更新已渲染过的元素列表是,它默认用“就地复用”策略。如果数据项的顺序被改变,Vue将不是移动DOM元素来匹配数据项的改变,而是简单复用此处每个元素,并且确保它在特定索引下显示已被渲染过的每个元素,那么v-for为什么能复用每个元素,又为什么能够渲染出每个元素呢?我们一起来看下v-for到底做了什么事情…
注意:

  • v-for循环的时候,key属性只能使用number或String。
  • key在使用的时候,必须使用v-bind属性绑定的形式,指定key的值。
  • 在组件中使用v-for循环的时候,或者在一些特殊情况中,如果v-for有问题,必须在使用v-for的同时,指定唯一的 字符串/数字 类型 :key值。

当 Vue.js 用v-for正在更新已渲染过的元素列表时,它默认用“就地复用”策略。如果数据项的顺序被改变,Vue 将不会移动 DOM 元素来匹配数据项的顺序, 而是简单复用此处每个元素,并且确保它在特定索引下显示已被渲染过的每个元素

接下来,我们通过解决其中的几个问题,来深入思考v-for的原理:
问题一:什么是“就地复用”?

举个简单的例子:
在一个玩具组装车间,小A、小B、小C、小D等共100个流水线工人在进行组装玩具的工作,每个人都正在进行自己的一辆组装玩具的任务。突然,小B生病请假了,但是小B的工作还没有完成,为了不影响整体进度,所有工人都依次往前补位,小C顶替了小B的工作,小D顶替了小C的工作,以此类推,这样做虽然麻烦,但是工作总算能够按期完成。
这 就是 就地复用的大致思路,试想:如果不采用就地复用,当小B缺席之后,流水线上的工人(包括小B之前的)都要重新排序,100个工人按照工号重新排序,重新获取自己的工作内容,这样子工作效率就大大降低。
DOM中,就地复用的是那些没有变化的元素,比如:

	<div v-for="item in list">
		<input/>
		{{ item.name }}
	</div>

在这段代码中,没有变化的元素是input,当我们删除item的某个元素时,item.message会发生变化,因此渲染的数据发生了变化,但是已经存在于dom中的input元素却会被就地复用,具体的演示效果如下:
Vue系列之(二)——Vue中的v-for到底做了什么?_第2张图片
问题二:如何解决接地复用产生的问题?
正如上面演示的效果那样,我们希望的是input元素也能被重新渲染,这个问题的解决方案在vue官方文档有详细说明,即需要给每一个列表项加上一个唯一的key属性

问题三:key属性是如何解决问题的,它的原理又是什么?
这个问题就涉及到了虚拟DOM的diff算法了,具体实现原理可以参考下面文章

问题四:没有添加key属性或者key属性不唯一 会出现什么问题?
key属性需要绑定一个唯一的值,但是在我们的实际项目中,习惯性会采用index作为key属性的值
因为index对应的value值是会变化的,例如:

	list: [
       {index: 0, value: 0},
      {index: 1, value: 1},
      {index: 2, value: 2}
     ]

当我们执行list.splice(1, 1)移除index = 1的项时,list数组就会变成:

	list: [
      {index: 0, value: 0},
      {index: 1, value: 2}
    ]

因为index是数组元素的索引,当某个元素被移除时,被移除元素后面的元素索引都会更新,也就是说index并不是唯一的,所以vue就会采用 就地复用 原则,这时如果页面上有类似于input这种跟value值没有绑定关系的元素时,这些元素将会被复用,有可能就得不到我们要的效果了。

小结相信用vue的人都会遇到这么一个列表渲染元素混乱的问题:key属性看似简单,但是关于列表渲染比较常见的坑还有数组和对象的监测和更新,还是很常见的。
欢迎各位技术大佬指正!

接下来,我们来看一下使用原生JS实现v-for渲染元素的效果,一起来学习吧。

参考原文地址:https://juejin.im/post/5c2746b4e51d450d50306db2
https://www.jqhtml.com/23868.html

你可能感兴趣的:(JS技术,vue)