Vue核心⑧(列表渲染)

举报
十八岁讨厌编程 发表于 2022/08/05 23:22:34 2022/08/05
【摘要】 文章目录 基本列表key的作用及原理列表过滤列表排序 基本列表 我们可以先用Vue创建一个基本的列表: <body> <div id="root"> ...

基本列表

我们可以先用Vue创建一个基本的列表:

<body>
    <div id="root">
        <ul>
            <li v-for="(person,index) in persons" :key="person.id">
                {{person.name}} -- {{person.age}} -- {{index}}
            </li>
        </ul>
    </div>
</body>
<script>
    new Vue({
        el:'#root',
        data:{
            persons:[
                {id:"1",name:"Tom",age:"18"},
                {id:"2",name:"Linda",age:"16"},
                {id:"3",name:"Jack",age:"17"}
            ]
        }
    })
</script>

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

注意:

  • 这里的key是必不可少的,他让每一个li都有一个特殊的标识。我们后面会做详细的介绍

  • in前面可以接收到两个返回值,一个是列表中的元素,另一个是列表索引。

  • 我们也可以利用列表索引的特殊独特性,将其作为key
    在这里插入图片描述

  • 如果接收多个返回值那个括号也可以省略。(但最好不要,有可能在一些老的脚手架中报错)

  • 这个in可以替换为of

除了遍历列表之外,我们还可以遍历对象类型:

<body>
    <div id="root">
        <ul>
            <li v-for="(person,index) in persons" :key="index">
                {{person.name}} -- {{person.age}} -- {{index}}
            </li>
        </ul>
        <ul>
            <li>学校概况</li>
            <li v-for="(inform,index) in school" :key="index">
                {{inform}} -- {{index}}
            </li>
        </ul>
    </div>
</body>
<script>
    new Vue({
        el:'#root',
        data:{
            persons:[
                {id:"1",name:"Tom",age:"18"},
                {id:"2",name:"Linda",age:"16"},
                {id:"3",name:"Jack",age:"17"}
            ],
            school:{
                name:"NEFU",
                type:'211',
                area:"3.3万公顷",
                num:"3.7万人"
            }
        }
    })
</script>

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

效果:
在这里插入图片描述

我们还可以遍历字符串

<body>
    <div id="root">
        <ul>
            <li v-for="(person,index) in persons" :key="index">
                {{person.name}} -- {{person.age}} -- {{index}}
            </li>
        </ul>
        <ul>
            <li>学校概况</li>
            <li v-for="(inform,index) in school" :key="index">
                {{inform}} -- {{index}}
            </li>
        </ul>
        <ul>
            <li v-for="(word,index) in str" :key="index">
                {{word}} -- {{index}}
            </li>
        </ul>
    </div>
</body>
<script>
    new Vue({
        el:'#root',
        data:{
            persons:[
                {id:"1",name:"Tom",age:"18"},
                {id:"2",name:"Linda",age:"16"},
                {id:"3",name:"Jack",age:"17"}
            ],
            school:{
                name:"NEFU",
                type:'211',
                area:"3.3万公顷",
                num:"3.7万人"
            },
            str:'hello'
        }
    })
</script>

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39

效果:
在这里插入图片描述
还可以遍历指定次数:

<body>
    <div id="root">
        <ul>
            <li v-for="(person,index) in persons" :key="index">
                {{person.name}} -- {{person.age}} -- {{index}}
            </li>
        </ul>
        <ul>
            <li>学校概况</li>
            <li v-for="(inform,index) in school" :key="index">
                {{inform}} -- {{index}}
            </li>
        </ul>
        <ul>
            <li v-for="(word,index) in str" :key="index">
                {{word}} -- {{index}}
            </li>
        </ul>
        <ul>
            <li v-for="(a,index) in 5" :key="index">
                {{a}} -- {{index}}
            </li>
        </ul>
    </div>
</body>
<script>
    new Vue({
        el:'#root',
        data:{
            persons:[
                {id:"1",name:"Tom",age:"18"},
                {id:"2",name:"Linda",age:"16"},
                {id:"3",name:"Jack",age:"17"}
            ],
            school:{
                name:"NEFU",
                type:'211',
                area:"3.3万公顷",
                num:"3.7万人"
            },
            str:'hello'
        }
    })
</script>

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44

效果:
在这里插入图片描述
总结:
在这里插入图片描述

key的作用及原理

首先我们先粗劣的理解key的作用:给节点进行一个标识,相当于他的身份证号

key这个属性属于Vue自用的,我们在源码中是看不到这个属性存在的。
在这里插入图片描述

然后我们着手来弄清楚一个问题:我们到底什么时候使用索引作为key?什么时候使用数据的编号作为key?两者有什么不同吗?

想要解决这个问题我们先要知道key的原理虚拟DOM的对比算法

我们给出如下案例:现在有三个人的信息,且每一个人的信息后面跟着一个input的框,点击按钮老刘被添加到列表的首位。

代码如下:

		<div id="root">
			<!-- 遍历数组 -->
			<h2>人员列表(遍历数组)</h2>
			<button @click.once="add">添加一个老刘</button>
			<ul>
				<li v-for="(p,index) of persons" :key="index">
					{{p.name}}-{{p.age}}
					<input type="text">
				</li>
			</ul>
		</div>

		<script type="text/javascript">
			Vue.config.productionTip = false
			
			new Vue({
				el:'#root',
				data:{
					persons:[
						{id:'001',name:'张三',age:18},
						{id:'002',name:'李四',age:19},
						{id:'003',name:'王五',age:20}
					]
				},
				methods: {
					add(){
						const p = {id:'004',name:'老刘',age:40}
						this.persons.unshift(p)
					}
				},
			})
		</script>

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

在使用index作为key的情况下,如果我们将input框中添加完信息后,再去加入老刘,数据会错位:
在这里插入图片描述
那么这是为什么呢?我们来分析一下它的运行过程。

首先Vue会拿着我们的初始数据形成虚拟DOM。在虚拟DOM中我们是可以看到key的!(真实DOM上是没有的)
在这里插入图片描述

在此时我们的页面上啥都没有,只是内存里面出现了三个虚拟的DOM节点

接下来将虚拟DOM转化为真实DOM。

这里注意用户是在真实DOM里输入的东西,虚拟DOM在内存里,用户是碰不到的。用户能操作的全是真实DOM。

用户完成输入后:
在这里插入图片描述
此时初始化流程结束!接下来添加了新的数据老刘,导致数据开始更新,更新完成后根据新数据Vue会再次生成对应的虚拟DOM:
在这里插入图片描述
此时Vue会在初始的虚拟DOM和新生成的虚拟DOM之间运用虚拟DOM算法。而这个对比就要依赖key

对比过程如下
在这里插入图片描述

按照顺序,在新的虚拟DOM中取出第一个,然后它会在初始的虚拟DOM中找到同样的key的那个节点。如下图所示:
在这里插入图片描述
找到了之后开始对比其中的两个节点。首先比较文本节点,发现两个不一样,再比较标签节点,是一样的。如下图所示:

两个input框是一样的,两个框里面输入的内容不同,只能说明真实DOM不同,但是虚拟DOM是一样的,都是空白。我们用户输入的内容是残留在真实DOM之中的

在这里插入图片描述

对比结果不一样的,代表不能复用,Vue只能将对应的虚拟DOM转化成真实DOM。而对比结果一样的,代表可以复用,Vue会将对应的老的真实DOM直接拿过来用。如图:
在这里插入图片描述
接下来的每一项对比均是如此。
在这里插入图片描述

如此我们可以知道数据错乱的原因。同时我们不难发现这样效率也很低下:因为使用index作为key,在修改之后,我们的文本节点全是新生成的,没有一个被复用

接下来我们分析一下,使用数据中的序号作为key时的运行过程:

前面的过程与前文一样,我们跳过直接来到对比算法部分:
在这里插入图片描述
先拿新虚拟DOM中的第一个节点出来,发现在初始虚拟DOM中没有与之相同的key,于是老刘这一项全都是由虚拟DOM转化为真实DOM得来的。
在这里插入图片描述

进行到张三、李四、王五的时候,在key值对应的情况下,其中的文本节点,标签节点均相同,于是这些全都可以复用,直接从旧的真实DOM之中拿过来使用。
在这里插入图片描述

如此我们知道使用数据的序号作为key值不会出现数据错乱的情况,且执行效率也非常高(多次的节点复用)

如果我们不写key,Vue会默认把遍历时候的索引值自动作为key。也就是相当于index作为key那种情况

当然我们如上的讨论,都是建立在往前面添加数据的情况下,说的抽象一点,就是破坏了数据原有的顺序的情况下,两者的区别。

如果你是在数据末尾添加新的数据,那么两者显然都可以使用!

总结:
在这里插入图片描述

列表过滤

我们做一个小的案例,搜索框中输入关键词,可以将列表进行筛选。
在这里插入图片描述
在这里插入图片描述
我们可以用两种方法实现这个案例:

  • 监视属性
  • 计算属性

①使用监视属性

	<body>
		<!-- 准备好一个容器-->
		<div id="root">
			<h2>人员列表</h2>
			<input type="text" placeholder="请输入名字" v-model="keyWord">
			<ul>
				<li v-for="(p,index) of filPerons" :key="index">
					{{p.name}}-{{p.age}}-{{p.sex}}
				</li>
			</ul>
		</div>

		<script type="text/javascript">
			Vue.config.productionTip = false
			
			//用watch实现
			new Vue({
				el:'#root',
				data:{
					keyWord:'',
					persons:[
						{id:'001',name:'马冬梅',age:19,sex:'女'},
						{id:'002',name:'周冬雨',age:20,sex:'女'},
						{id:'003',name:'周杰伦',age:21,sex:'男'},
						{id:'004',name:'温兆伦',age:22,sex:'男'}
					],
					filPerons:[]
				},
				watch:{
					keyWord:{
						immediate:true,
						handler(val){
							this.filPerons = this.persons.filter((p)=>{
								return p.name.indexOf(val) !== -1
							})
						}
					}
				}
			}) 

		</script>

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41

代码说明:

  • persons是原本,而filPerons是要呈现的副本。
  • 我们还需要了解数组中filter的使用方法

    filter() 方法创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素。
    注意: filter() 不会对空数组进行检测。
    注意: filter() 不会改变原始数组。
    语法:
    array.filter(function(currentValue,index,arr), thisValue)
    里面的function要返回一个布尔值,从而决定什么元素在新的数组中
    在这里插入图片描述

  • 配置immediate:true是因为初始化的时候也要调用一下handler,否则刚打开网页的时候是这样显示的:
    在这里插入图片描述
  • 为了动态的获得用户的输入内容,我们使用的是双向数据绑定。在代码中我们是通过keyword去获取的。

②使用计算属性

	<body>
		<!-- 准备好一个容器-->
		<div id="root">
			<h2>人员列表</h2>
			<input type="text" placeholder="请输入名字" v-model="keyWord">
			<ul>
				<li v-for="(p,index) of filPerons" :key="index">
					{{p.name}}-{{p.age}}-{{p.sex}}
				</li>
			</ul>
		</div>

		<script type="text/javascript">
			Vue.config.productionTip = false

			//用computed实现
			new Vue({
				el:'#root',
				data:{
					keyWord:'',
					persons:[
						{id:'001',name:'马冬梅',age:19,sex:'女'},
						{id:'002',name:'周冬雨',age:20,sex:'女'},
						{id:'003',name:'周杰伦',age:21,sex:'男'},
						{id:'004',name:'温兆伦',age:22,sex:'男'}
					]
				},
				computed:{
					filPerons(){
						return this.persons.filter((p)=>{
							return p.name.indexOf(this.keyWord) !== -1
						})
					}
				}
			}) 
		</script>

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

当用户的输入内容发生变化时,造成了计算属性filPerons的依赖属性发生了变化,从而造成了filPerons发生变化,于是Vue会重新解析模板。

这个地方不用考虑列表初始为空的情况,因为在计算属性中get的调用有两个时机:
在这里插入图片描述

同时从代码量上我们也可以推测出来优先使用computed。

列表排序

我们直接通过案例来理解。我们借用上篇中的案例,在此基础上添加一个排序的小功能。如图所示:
在这里插入图片描述
我们使用计算属性来写:

	<body>
		<!-- 准备好一个容器-->
		<div id="root">
			<h2>人员列表</h2>
			<input type="text" placeholder="请输入名字" v-model="keyWord">
            <button @click="typeNum = 0">原顺序</button>
            <button @click="typeNum = 1">年龄升序</button>
            <button @click="typeNum = 2">年龄降序</button>
			<ul>
				<li v-for="(p,index) of filPerons" :key="index">
					{{p.name}}-{{p.age}}-{{p.sex}}
				</li>
			</ul>
		</div>

		<script type="text/javascript">
			Vue.config.productionTip = false

			//用计算属性
			new Vue({
				el:'#root',
				data:{
					keyWord:'',
                    typeNum:0, //默认先原顺序排列
					persons:[
						{id:'001',name:'马冬梅',age:56,sex:'女'},
						{id:'002',name:'周冬雨',age:30,sex:'女'},
						{id:'003',name:'周杰伦',age:17,sex:'男'},
                        {id:'004',name:'温兆伦',age:31,sex:'男'},
                        {id:'005',name:'哇哈哈',age:65,sex:'男'},
                        {id:'006',name:'加多宝',age:72,sex:'男'},
                        {id:'007',name:'红双喜',age:27,sex:'男'},
					]
				},
                computed:{
                    filPerons(){
                        // 先进行数据筛选
                        let temp  = this.persons.filter((value) =>{
                            return value.name.indexOf(this.keyWord) != -1
                        })

                        if(this.typeNum){
                            return this.typeNum == 1 ? temp.sort((a,b) => {return a.age - b.age}) : temp.sort((a,b) => {return b.age - a.age})
                        }

                        return temp
                    }
                }

			}) 
		</script>

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51

复习:js数组中的排序方法:
在这里插入图片描述
语法:array.sort(sortfunction)
在这里插入图片描述

想要实现这个案例我们只需要得到用户的排序需求,以及调用数组的api进行相应处理即可。我们在属性中添加一项来接受客户的具体排序需求。并且通过对按钮的绑定事件对其进行修改。通过if判断来决定进行哪种排序逻辑。

可能会有人就觉得直接在按钮上绑定事件对数组进行排序不可以吗。这个方法在使用计算属性的时候不是很方便。我们在绑定的事件中对数组进行修改后,计算属性会调用相应的set函数(我们自己去编写),而此时的计算属性只有一个依赖typeNum,我们在set函数中也只能对他进行修改。我们相当于绕了一大圈去做一件相同的事。

文章来源: blog.csdn.net,作者:十八岁讨厌编程,版权归原作者所有,如需转载,请联系作者。

原文链接:blog.csdn.net/zyb18507175502/article/details/125164190

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。