6.Vue - 渲染、列表中key的原理和作用、列表排序

目录

一、条件渲染

1.1 v-if

1.2 v-show

1.3 template

二、列表渲染 v-for

2.1 遍历数组

2.2 遍历对象

2.3 遍历字符串

2.4 遍历指定次数

三、列表渲染 key 原理

3.1 问题演示

3.2 解决问题

3.3 原理

3.1.1 index 作为 key

3.1.2 id 作为 key

3.4 总结

四、列表过滤

4.1 watch 实现

4.2 computed 实现

五、列表排序


一、条件渲染

当符合某个条件后,我们就选用某种样式

1.1 v-if

适用于:切换频率较低的场景

特点:不展示的DOM元素直接被移除,在页面源码中无法看到

注意:v-if,v-else-if 、 else if,div要紧紧的挨在一起,不能打断

            <!--  v-else-if 类似java中if  else if判断 -->
            <!-- 这四个div要紧紧的挨在一起,不能打断 -->
            <div v-if="n===1" >Angular</div>
            <div v-else-if="n===2" >React</div>
            <div v-else-if="n===3" >Vue</div>
            <div v-else >6666666</div>

<!-- 使用v-if做条件渲染:在网页查看源码时,将不会看到下面这个html语句 -->
<h2 v-if="false">欢迎来到{{name}}学习</h2>

下面便是被打断的演示,此时"Vue"与"6666666"就不会再被展示了

            <div v-if="n===1" >Angular</div>
            <div v-else-if="n===2" >React</div>
​
            <div>React</div>
​
            <div v-else-if="n===3" >Vue</div>
            <div v-else >6666666</div>

1.2 v-show

写法:v-show=“表达式”

适用于:切换频率较高的场景

特点:不展示DOM元素未被移除,仅仅是使用上隐藏掉,在页面的源代码中还是能看到的

备注:使用v-if时,元素可能无法获取到,而使用v-show一定可以获取到

备注的意思是使用v-show修饰的元素虽然不在页面中展示,但是可以拿到这个元素的,但是使用v-if的话就拿不到

<!-- 使用v-show做条件渲染:确切的说这个底层是display:none -->
<h2 v-show="false">欢迎来到{{name}}学习</h2>

v-show的底层其实就是调整 style="display:none"的值

image-20231031112333059

1.3 template

当我们对某几个标签添加相同的样式的时候,我们就可以使用template标签,在标签上添加v-if属性

好处:不影响整体样式。

备注:template标签不影响整体结构,只是把下面这三个标签给包裹起来,在页面查看源码的时候也不会发现template标签

此标签只能使用v-if,不能使用v-show

             <!-- template标签不影响整体结构,只是把下面这三个标签给包裹起来,在页面查看源码的时候也不会发现template标签
                   此标签只能使用v-if,不能使用v-show -->
             <template v-if="n===1">
                <h2>你好</h2>
                <h2>中国</h2>
                <h2>北京</h2>
             </template>

二、列表渲染 v-for

用于展示列表数据

语法:v-for="(item,index) in xxx" :key="yyy"

可遍历:数组、对象、字符串(用的很少)、指定次数(用的很少)

2.1 遍历数组

v-for类似java中foreach遍历,persons里面有几个值,我们在页面就会呈现几个

:key="p.id"让每一个li都有一个唯一的标识,类似数据库中的主键

{{p}} 这么输出的话,会把数据直接输出,我们一般不这样

<li v-for="p in persons" :key="p.id">
<!-- {{p}}  这么输出的话,会把数据直接输出,我们一般不这样 -->
     {{p.name}}-{{p.age}}
</li>

其实这个地方不写 :key="p.id" 也是可以的,也不会报错,但是最好一定要写上

而且在遍历的时候可以接受好几个参数,比如 (a,b,c) in persons

a代表我们数据

b代表索引值

c及其以后就没有参数了

除此之外,还可以 (p,index) of persons,就是把关键字in换成of,这是API的历史遗留问题

index是索引值,这个地方会有索引值,类似数组的下标 :key="p.id" 这个地方不用p.id也可以,我们使用index ,因为index也是唯一的,类似数组下标 :key这个标签特别重要,动态绑定数据

 <ul>
   <li v-for="(p,index) in persons" :key="index">
        <!-- {{p}}  这么输出的话,会把数据直接输出,我们一般不这样 -->
        {{p.name}}-{{p.age}}-{{index}}
   </li>
</ul>

如果要有顺序的话,就需要数组来存储 这里的id类似数据库中的主键

                data:{
                  persons:[
                    {id:'001',name:'张三',age:18},
                    {id:'002',name:'李四',age:18},
                    {id:'003',name:'王五',age:20}
                  ]
                },

效果图

image-20231101175801150

2.2 遍历对象

            <h2>汽车信息</h2>
            <ul>
                <li v-for="(value,k) in car" :key="k" >
                    {{value}}-{{k}}
                </li>
            </ul>

                data:{
                  car:{
                    name:'奥迪A8',
                    price:"666666",
                    color:'黑色'
                  }
                },

效果图

image-20231101180243573

2.3 遍历字符串

<ul>
    <li v-for="(value,k) in str" :key="k" >       
          {{value}}-{{k}}
    </li>
</ul>

data:{
    str:'hello'
}

image-20231101180323445

2.4 遍历指定次数

第一个参数是数值。第二个参数是索引值

<ul>
    <li v-for="(number,index) in 5" :key="index" >   
        {{number}}-{{index}}
    </li>
</ul>

三、列表渲染 key 原理

说白了key就是一个身份表示,类似人的身份证号

如果在写代码时并没有指定:key,我们会把index默认的作为key

通过我们查看发现,我们在源代码中是有:key的,但是在网页上并不会显示,原因就是这个:key是vue内部在用,用完就干掉了

img

3.1 问题演示

如下, :key值是index的时候,会出现一系列的问题(不同的情景不一样,可能index不会出问题)

添加一个“老刘”角色,将其添加在数组的最前面

  <h2>人员列表</h2>
            <button @click.once="add">添加一个老刘</button>
        <ul>
            <!-- key标签属性非常重要 -->
            <!-- p代表着persons中的一个对象 -->
            <li v-for="(p,index) in persons" :key="index">
                {{p.name}}-{{p.age}}-{{index}}
                <input type="text">
            </li>
        </ul>

new Vue({
            el: "#root",
            data: {
                persons: [
                    { id: '001', name: '张三', age: 18 },
                    { id: '002', name: '李四', age: 18 },
                    { id: '003', name: '王五', age: 20 }
                ]
            },
            methods:{
                 add(){
                    const p ={ id: '004', name: '老刘', age: 18 }
                    this.persons.unshift(p)
                 }
            }
        })

点击按钮后的效果

image-20231102112154843

演示问题

在文本框中输入内容,之后再点击添加老刘

image-20231102112322533

变成了如下所示的情况,文本框不会随着人名流动

除此之外还存在一个效率低的问题

image-20231102112345961

3.2 解决问题

将key改成p.id即可

 <h2>人员列表</h2>
            <button @click="add">添加一个老刘</button>
            <ul>
                <!-- index就是索引值,这个地方会有索引值,类似数组的下标 -->
                <!-- :key="p.id"  这个地方不用p.id也可以,我们使用index ,因为index也是唯一的,类似数组下标-->、
                <!-- :key这个标签特别重要,动态绑定数据 -->
                <li v-for="(p,index) in persons" :key="p.id">
                    <!-- {{p}}  这么输出的话,会把数据直接输出,我们一般不这样 -->
                    {{p.name}}-{{p.age}}-{{index}}
                    <input type="text">
                </li>
            </ul>

3.3 原理

3.1.1 index 作为 key

假如遍历的时候不指定:key是哪个,也会默认将index作为key

  1. Vue将我们写的数据生成虚拟的DOM

    真实DOM是没有key的,但是虚拟DOM是有key的,如果虚拟DOM没有key,Vue就没有办法高效的工作了

image-20231109142822346

截止目前,我们的页面啥也没有,只是内存出现了三个结点

  1. 将虚拟DOM转换成真实DOM

image-20231109143048111

  1. 用户在真实DOM的文本框输入数据后,新的数据出现。随后就要根据新的数据生成新的虚拟DOM

    image-20231109143316311

  1. Vue进行虚拟DOM的对比算法,对比的时候依赖的就是key

image-20231109143533491

对比规则

  • 旧虚拟DOM找到了与新虚拟DOM相同的key

    若虚拟DOM中内容没变,直接使用之前的真实DOM

    若虚拟DOM中内容变了,则生成新的真实DOM,随后替换掉页面中之前的真实DOM

  • 旧虚拟DOM中未找到与新虚拟DOM中相同的key

    创建新的真实DOM,随后渲染到页面

  1. 对比结果

image-20231109144312301

3.1.2 id 作为 key

其实和index作为key差不多

image-20231109144641242

3.4 总结

  • 虚拟DOM中key的作用 key是虚拟对象的标识,当数据发生变化时,Vue会根据新数据生成新的虚拟DOM,随后Vue进行新虚拟DOM与旧虚拟DOM的差异比较。

  • 对比规则

    • 旧虚拟DOM找到了与新虚拟DOM相同的key

      若虚拟DOM中内容没变,直接使用之前的真实DOM

      若虚拟DOM中内容变了,则生成新的真实DOM,随后替换掉页面中之前的真实DOM

    • 旧虚拟DOM中未找到与新虚拟DOM中相同的key

      创建新的真实DOM,随后渲染到页面

  • 用index作为key可能引发的问题

    • 若对数据进行逆序添加、逆序删除等破坏顺序操作

      会产生没有必要的真实DOM更新==》界面效果没问题,但效率低

    • 如果结构中还包含输入类DOM:

      会产生错误DOM更新==》界面有问题

  • 开发中如何选择key

    • 最好使用每条数据的唯一标识作为key,比如id、手机号、身份证号、学号等(类似数据库中主键)

    • 如果不存在对数据的逆序添加、逆序删除等破坏顺序的操作,仅用于渲染列表用于展示,使用index作为key是没有问题的

四、列表过滤

初始界面

image-20231109153701864

4.1 watch 实现

监视属性基础知识:4.Vue-计算属性、监视属性、深度监视、计算属性与监视属性对比计算属性深度我爱布朗熊的博客-CSDN博客

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title> 初识vue</title>
        <!--引入vue    引入之后,全局就多了一个vue这个构造函数-->
        <script type="text/javascript" src="../js/vue.js"></script> 
    </head>
    <body>
        <div id="root">
            <ul>
                <h2>人员列表</h2>
                <!-- 双向绑定一下 -->
                <input type="text" placeholder="请输入名字"  v-model="keyWords">
                <li v-for="(p,index) in  filPersons" :key="p.id" >
                    {{p.name}}-{{p.age}}-{{p.sex}}
                </li>
            </ul>
 
        </div>
 
        <script type="text/javascript">
            //阻止vue在启动时生成生产提示
            Vue.config.productionTip=false
            
            new Vue({
                el:'#root',
                data:{
                  //关键词,后面要用这个进行过滤
                  keyWords:'',
                  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:'男'}
                  ],
                  filPersons:[]
                },
                watch:{
                    // 监视谁我们就写谁
                   keyWords:{
                    // 初始化时让handler调用一下,如果不调用的话,初始页面会没有内容
                    // 前提条件:所有的字符串.indexOf("")空字符串,返回值都是0
                     immediate:true,
                     handler(newValue,oldValue){
                        // 过滤
                        // filter规律之后,并不会影响我们初始的数组,而是生成一个全新的数组
                        //  我们不能更改直接赋值到原数组,否则会导致我们查询的内容越来越少,最后甚至没有了
                        this. filPersons= this.persons.filter((p)=>{
                            // 函数体
                            // return 后面加的语句使我们要的数据
                            // indexOf 方法(判断字符串里面是否包含指定字符),当含有括号内的字符串的时候,会返回下标是第几位(从零开始算
                            //当不包含的时候,就会返回-1
                            return p.name.indexOf(newValue) !==-1
                        })
                     }
                   }
                },
                methods:{
 
                }
            })
 
        </script>   
    </body>
</html>
 

4.2 computed 实现

计算属性基础知识:4.Vue-计算属性、监视属性、深度监视、计算属性与监视属性对比计算属性深度我爱布朗熊的博客-CSDN博客

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title> 初识vue</title>
        <!--引入vue    引入之后,全局就多了一个vue这个构造函数-->
        <script type="text/javascript" src="../js/vue.js"></script> 
    </head>
    <body>
        <div id="root">
            <ul>
                <h2>人员列表</h2>
                <!-- 双向绑定一下 -->
                <input type="text" placeholder="请输入名字"  v-model="keyWords">
                <li v-for="(p,index) in  filPersons" :key="p.id" >
                    {{p.name}}-{{p.age}}-{{p.sex}}
                </li>
            </ul>
 
        </div>
 
        <script type="text/javascript">
            //阻止vue在启动时生成生产提示
            Vue.config.productionTip=false
            
          const vm=  new Vue({
                el:'#root',
                data:{
                  keyWords:'',
                  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:'男'}
                  ],
                 
                },
 
                //在计算属性中依赖了keyWords,当keyWords一变,就会调用filPersons()
                computed:{
                    // 这个形式是缩写,当getter函数使用
                    // 初次读取的时候会调用一下,当依赖的数据发生变化时也会调用一下
                    filPersons(){
                        // 这个return是计算属性规定的
                        return this.persons.filter((p)=>{
                            // 这个return是filter规定的
                            return p.name.indexOf(this.keyWords) !==-1
                        })
                    }
                }
            })
 
        </script>   
    </body>
</html>

五、列表排序

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title> 初识vue</title>
        <!--引入vue    引入之后,全局就多了一个vue这个构造函数-->
        <script type="text/javascript" src="../js/vue.js"></script> 
    </head>
    <body>
        <div id="root">
            <h2>人员列表</h2>
            <!-- 双向绑定一下 -->
            <input type="text" placeholder="请输入名字"  v-model="keyWords">
            <button @click="sortType=2" >年龄升序</button>
            <button @click="sortType=1" >年龄降序</button>
            <button @click="sortType=0" >原顺序</button>
 
            <ul>
                <li v-for="(p,index) in  filPersons" :key="p.id" >
                    {{p.name}}-{{p.age}}-{{p.sex}}
                </li>
            </ul>
 
        </div>
 
        <script type="text/javascript">
            //阻止vue在启动时生成生产提示
            Vue.config.productionTip=false
            
          const vm=  new Vue({
                el:'#root',
                data:{
                  keyWords:'',
                //   0原顺序 1降序 2升序
                  sortType:0,  
                  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:{
                    // 这个形式是缩写,当getter函数使用
                    // 初次读取的时候会调用一下,当依赖的数据发生变化时也会调用一下
                    filPersons(){
                        // 我们把这个地方的return取消,不着急return
                       const arr= this.persons.filter((p)=>{
                            // 这个return是filter规定的
                            
                            return p.name.indexOf(this.keyWords) !==-1
                        })
 
                        if(this.sortType){
                            // 运行到这里说明不是0
                            // sort排序回改变原数组。sort排序的时候会收到两个数据项,前减后是升序,后减前是降序
                            arr.sort( (p1,p2)=>{
                                // 三目运算  sortType等于1 年龄降序 sortType等于2 年龄升序    
                                return this.sortType === 1 ? p2.age-p1.age : p1.age-p2.age
                            })
                        }
                        //当 this.sortType===0时,会直接跳过if来到这里(原始数据不会改变,所以就是原顺序
                        return arr
                    }
                }
            })
 
        </script>   
    </body>
</html>

原顺序

img

升序

img

降序

img

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Vue3 ,你可以使用 `v-for` 指令来循环渲染列表,同时使用 `Array.sort()` 方法来对列表进行排序。 下面是一个基本的示例: 在模板使用 `v-for` 指令来循环渲染列表,并使用 `Array.sort()` 方法对列表进行排序: ```html <template> <div> <h2>Students List:</h2> <ul> <li v-for="student in sortedStudents" :key="student.id"> {{ student.name }} - {{ student.score }} </li> </ul> </div> </template> <script> export default { data() { return { students: [ { id: 1, name: "Tom", score: 90 }, { id: 2, name: "Jerry", score: 80 }, { id: 3, name: "Alice", score: 95 }, { id: 4, name: "Bob", score: 85 }, ], }; }, computed: { // 使用 computed 属性来定义一个计算属性 sortedStudents // 在这个计算属性,我们使用 Array.sort() 方法来按照分数(score)对学生列表进行排序 sortedStudents() { return this.students.sort((a, b) => { return b.score - a.score; }); }, }, }; </script> ``` 在上面的代码,我们首先定义了一个包含学生信息的数据 `students`,然后使用 `computed` 属性来定义一个计算属性 `sortedStudents`,在这个计算属性,我们使用 `Array.sort()` 方法来按照分数(`score`)对学生列表进行排序。最后,我们在模板使用 `v-for` 指令来循环渲染排序后的学生列表。 注意事项: - 在 Vue3 ,计算属性的定义方式与 Vue2 有所不同。需要使用 `computed` 属性来定义计算属性。 - 使用 `v-for` 循环渲染列表时,需要为每个列表项指定一个唯一的 `key` 属性,以提高列表渲染性能。在上面的示例,我们使用 `:key="student.id"` 来为每个列表项指定一个唯一的 `id`。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我爱布朗熊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值