Vue中的数据渲染【4】

目录

1.页面样式绑定:

1.概述:

页面样式绑定在 Vue 中是一种将样式与数据动态关联起来的方式,使得页面的样式可以根据数据的变化而自动更新。

2.绑定方式:

1.通过类名绑定:
1.通过动态类名绑定:(:class)
plain 复制代码
  <!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
<!--准备样式        -->
       //基础样式:宽400,长100,实线黑色边框(宽1)
        .basic {
            width: 400px;
            height: 100px;
            border: 1px solid black;
        }
        //容器1样式:实线红色边框,宽4,容器背景渐变色
        .box1 {
            border: 4px solid red;
            /*background-color: rgba(255, 255, 0, 0.6);*/
            background: linear-gradient(30deg, yellow, pink, orange, yellow);
        }
        //容器2样式:虚线边框,宽4,边框颜色rgb,容器背景灰色
        .box2 {
            border: 4px dashed rgb(2, 197, 2);
            background-color: gray;
        }
         //容器3样式:容器背景蓝色
        .box3 {
            background-color: skyblue;
        }
          //容器4样式:容器背景黄绿色
        .box4 {
            background-color: yellowgreen;
        }
        // //容器5样式:字体大小30,为字体添加阴影效果
        .box5 {
            font-size: 30px;
            text-shadow: 2px 2px 10px red;
        }
        //容器6样式:设置边框圆角
        .box6 {
            border-radius: 20px;
        }

    </style>
</head>
<body>
<!--2.准备一个容器-->
<div id="root">
    <div class="basic" :class="classStr">
        {{name}}
    </div>
</div>
<!--1.引入Vue js 文件-->
<script src="vue/vue.js"></script>
<script type="text/javascript">
    //3.创建Vue对象
    let vm = new Vue({
        data() {
            return {
                name: '猿究院',
                classStr: 'box2',

             }
        }
    }).$mount("#root");
</script>
</body>
</html>
复制代码
 上面案例中我们定义了一些样式,并在div子容器中通过指令语法动态绑定了data属性中的对应属性,实现了将data属性值对应的容器样式动态的绑定到了div子容器中(注意在div子容器绑定样式时有两个类名,实际上他们对应的样式效果是叠加的)实际样式效果如下所示:
2.通过类名数组绑定:
plain 复制代码
  <!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
<!--准备样式        -->
       //基础样式:宽400,长100,实线黑色边框(宽1)
        .basic {
            width: 400px;
            height: 100px;
            border: 1px solid black;
        }
        //容器1样式:实线红色边框,宽4,容器背景渐变色
        .box1 {
            border: 4px solid red;
            /*background-color: rgba(255, 255, 0, 0.6);*/
            background: linear-gradient(30deg, yellow, pink, orange, yellow);
        }
        //容器2样式:虚线边框,宽4,边框颜色rgb,容器背景灰色
        .box2 {
            border: 4px dashed rgb(2, 197, 2);
            background-color: gray;
        }
         //容器3样式:容器背景蓝色
        .box3 {
            background-color: skyblue;
        }
          //容器4样式:容器背景黄绿色
        .box4 {
            background-color: yellowgreen;
        }
        // //容器5样式:字体大小30,为字体添加阴影效果
        .box5 {
            font-size: 30px;
            text-shadow: 2px 2px 10px red;
        }
        //容器6样式:设置边框圆角
        .box6 {
            border-radius: 20px;
        }

    </style>
</head>
<body>
<!--2.准备一个容器-->
<div id="root">
   <div class="basic" :class="classArr">
        {{name}}
    </div>
</div>
<!--1.引入Vue js 文件-->
<script src="vue/vue.js"></script>
<script type="text/javascript">
    //3.创建Vue对象
    let vm = new Vue({
        data() {
            return {
                name: '猿究院',
               classArr: ['box4', 'box5', 'box6'],

             }
        }
    }).$mount("#root");
</script>
</body>
</html>

上面案例中通过类名数组动态绑定多个类对应的容器样式,再将这些容器样式进行叠加后绑定到div子容器中,最终div子容器的样式效果如下所示:

3.通过类名对象进行绑定:
plain 复制代码
  <!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
<!--准备样式        -->
       //基础样式:宽400,长100,实线黑色边框(宽1)
        .basic {
            width: 400px;
            height: 100px;
            border: 1px solid black;
        }
        //容器1样式:实线红色边框,宽4,容器背景渐变色
        .box1 {
            border: 4px solid red;
            /*background-color: rgba(255, 255, 0, 0.6);*/
            background: linear-gradient(30deg, yellow, pink, orange, yellow);
        }
        //容器2样式:虚线边框,宽4,边框颜色rgb,容器背景灰色
        .box2 {
            border: 4px dashed rgb(2, 197, 2);
            background-color: gray;
        }
         //容器3样式:容器背景蓝色
        .box3 {
            background-color: skyblue;
        }
          //容器4样式:容器背景黄绿色
        .box4 {
            background-color: yellowgreen;
        }
        // //容器5样式:字体大小30,为字体添加阴影效果
        .box5 {
            font-size: 30px;
            text-shadow: 2px 2px 10px red;
        }
        //容器6样式:设置边框圆角
        .box6 {
            border-radius: 20px;
        }

    </style>
</head>
<body>
<!--2.准备一个容器-->
<div id="root">
  <div class="basic" :class="classObject">
        {{name}}
    </div>
</div>
<!--1.引入Vue js 文件-->
<script src="vue/vue.js"></script>
<script type="text/javascript">
    //3.创建Vue对象
    let vm = new Vue({
        data() {
            return {
                name: '猿究院',
               classObject: {
                    box1: true,
                    box5: true,
                    box3: false
                },

             }
        }
    }).$mount("#root");
</script>
</body>
</html>
复制代码
  在此案例中我们通过类对象进行样式绑定,在data中定义一个ClassObiect的对象,此对象的每个属性都表示一个容器样式的容器名,值为布尔值,true表示启用该容器样式,false则表示不用,最终div子容器样式效果如下所示:
2.内联样式绑定:(:sytle)
1.通过样式对象语法绑定:
plain 复制代码
  <!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
<!--准备样式        -->
       //基础样式:宽400,长100,实线黑色边框(宽1)
        .basic {
            width: 400px;
            height: 100px;
            border: 1px solid black;
        }
        //容器1样式:实线红色边框,宽4,容器背景渐变色
        .box1 {
            border: 4px solid red;
            /*background-color: rgba(255, 255, 0, 0.6);*/
            background: linear-gradient(30deg, yellow, pink, orange, yellow);
        }
        //容器2样式:虚线边框,宽4,边框颜色rgb,容器背景灰色
        .box2 {
            border: 4px dashed rgb(2, 197, 2);
            background-color: gray;
        }
         //容器3样式:容器背景蓝色
        .box3 {
            background-color: skyblue;
        }
          //容器4样式:容器背景黄绿色
        .box4 {
            background-color: yellowgreen;
        }
        // //容器5样式:字体大小30,为字体添加阴影效果
        .box5 {
            font-size: 30px;
            text-shadow: 2px 2px 10px red;
        }
        //容器6样式:设置边框圆角
        .box6 {
            border-radius: 20px;
        }

    </style>
</head>
<body>
<!--2.准备一个容器-->
<div id="root">
  <div class="basic" :style="styleObject">
        {{name}}
    </div>
</div>
<!--1.引入Vue js 文件-->
<script src="vue/vue.js"></script>
<script type="text/javascript">
    //3.创建Vue对象
    let vm = new Vue({
        data() {
            return {
                name: '猿究院',
                styleObject: {
                    fontSize: '40px',
                    color: 'red'
                },

             }
        }
    }).$mount("#root");
</script>
</body>
</html>
  

说明:此时通过内联式绑定样式效果,在data的styleObject对象中就不能在写容器样式对应的容器名了,而要写具体的样式效果。并且由于内联式级别高于类选择器,因此basic的样式效果会被覆盖。此时div子容器的样式效果如下图所示:

2.通过样式数组语法绑定:
plain 复制代码
  <!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
<!--准备样式        -->
       //基础样式:宽400,长100,实线黑色边框(宽1)
        .basic {
            width: 400px;
            height: 100px;
            border: 1px solid black;
        }
        //容器1样式:实线红色边框,宽4,容器背景渐变色
        .box1 {
            border: 4px solid red;
            /*background-color: rgba(255, 255, 0, 0.6);*/
            background: linear-gradient(30deg, yellow, pink, orange, yellow);
        }
        //容器2样式:虚线边框,宽4,边框颜色rgb,容器背景灰色
        .box2 {
            border: 4px dashed rgb(2, 197, 2);
            background-color: gray;
        }
         //容器3样式:容器背景蓝色
        .box3 {
            background-color: skyblue;
        }
          //容器4样式:容器背景黄绿色
        .box4 {
            background-color: yellowgreen;
        }
        // //容器5样式:字体大小30,为字体添加阴影效果
        .box5 {
            font-size: 30px;
            text-shadow: 2px 2px 10px red;
        }
        //容器6样式:设置边框圆角
        .box6 {
            border-radius: 20px;
        }

    </style>
</head>
<body>
<!--2.准备一个容器-->
<div id="root">
  <div class="basic" :style="styleArr">
        {{name}}
    </div>
</div>
<!--1.引入Vue js 文件-->
<script src="vue/vue.js"></script>
<script type="text/javascript">
    //3.创建Vue对象
    let vm = new Vue({
        data() {
            return {
                name: '猿究院',
                 styleArr: [
                    {
                        fontSize: '40px',
                        color: 'blue'
                    },
                    {
                        backgroundColor: 'yellowgreen'
                    }
                ]
             }
        }
    }).$mount("#root");
</script>
</body>
</html>
   

说明:此时通过样式数组进行样式效果绑定,将样式效果以数组的形式进行定义,最终叠加绑定到div子容器上,注意:basic样式仍会被覆盖;

2.条件渲染:

1.概述:

复制代码
 在vue中通过v-if,v-else-if,v-else等语句进行条件判断当前内容是否执行渲染展示

2.语法:

plain 复制代码
  v-if='条件1'.....
  v-else-if='条件2'....
  v-else-if='条件3'....
   ......
  v-else ........

3.使用方法:

plain 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<!--2.准备一个容器-->
<div id="root">
    <h2>当前count的值是:{{count}}</h2>
    <button @click="count++">点击count++</button>
    <div v-if="count==1">v-if....</div>
    <div v-else-if="count==2">v-else-if  ....</div>
    <div v-else-if="count==3">v-else-if ....</div>
    <div v-else>v-else ....</div>

</div>
<!--1.引入Vue js 文件-->
<script src="vue/vue.js"></script>
<script type="text/javascript">
    //3.创建Vue对象
    let vm = new Vue({
        data() {
            return {
                count: 0
            }
        }
    }).$mount("#root");
</script>
</body>
</html>
    
复制代码
  说明:上述案例中通过v-if,v-else-if,v-else对变量count的值进行判断,根据count的不同值,在页面渲染展示不同的内容

![](https://cdn.nlark.com/yuque/0/2024/png/45532635/1732158019754-79e8d49d-c41f-4bed-b8ee-913d72018687.png)

4.注意事项;

复制代码
   v-if 指令会移除当条件不满足时页面的DOM元素;
复制代码
   v-else-if指令执行过程中不能被其他业务中断,否则中断之后的逻辑判断不再执行;
复制代码
   v-if指令适合执行内容隐藏-显示切换频率不高的场景,如果切换频率较高,则应使用v-show指令,因为v-show指令不会删除不满足条件的DOM元素,而是会将其通过CSS隐藏起来,因此效率比较高;

3.列表渲染

1.概述:

列表渲染主要是通过v-for指令对数组,对象,字符串等数据进行遍历;

2.语法:

plain 复制代码
v-for="(item,index)  in 遍历对象" :key='对象的键'   

3.使用:

1.遍历数组:
plain 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<!--2.准备一个容器-->
<div id="root">
    <!--   遍历数组  -->
    <ul>
        <!--        v-for  :key-->
        <!--     item 循环的每一个值,index 下标   -->
        <!--        <li v-for="item  in persons">-->
        <li v-for="(item,index)  in persons" :key="item.id">
            {{index}}-{{item.name}}-{{item.age}}
        </li>
    </ul>
</div>
<!--1.引入Vue js 文件-->
<script src="vue/vue.js"></script>
<script type="text/javascript">
    //3.创建Vue对象
    let vm = new Vue({
        data() {
            return {
                persons: [
                    {id: '001', name: '张三', age: 20},
                    {id: '002', name: '李四', age: 22},
                    {id: '003', name: '王武 ', age: 18}
                ],
             }
        }
    }).$mount("#root");
</script>
</body>
</html>

说明:上面案例中我们使用v-for指令对person数组进行遍历展示,注意我们的key在选择时使用的时元素的id,而没有使用元素在数组中的下标index,主要是为了保证它的唯一性,当使用index作为key时,再执行一些逆序操作时可能会存在一些问题;

2.遍历对象:
plain 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<!--2.准备一个容器-->
<div id="root">
  <!--   遍历对象  -->
    <ul>
        <!-- (item 值,index 属性名) -->
        <li v-for="(item,index)  in numbers" :key="index">
            {{index}}-{{item}}
        </li>
    </ul>
</div>
<!--1.引入Vue js 文件-->
<script src="vue/vue.js"></script>
<script type="text/javascript">
    //3.创建Vue对象
    let vm = new Vue({
        data() {
            return {
                numbers: {
                    a: 1,
                    b: 2,
                    c: 3
                },
             }
        }
    }).$mount("#root");
</script>
</body>
</html>
 
3.遍历字符串:
plain 复制代码
 <!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<!--2.准备一个容器-->
<div id="root">
   <!--   遍历字符串  -->
    <ul>
        <!-- (item 字符,index 下标) -->
        <li v-for="(item,index)  in str" :key="index">
            {{index}}-{{item}}
        </li>
    </ul>
</div>
<!--1.引入Vue js 文件-->
<script src="vue/vue.js"></script>
<script type="text/javascript">
    //3.创建Vue对象
    let vm = new Vue({
        data() {
            return {
              str: 'hello'
             }
        }
    }).$mount("#root");
</script>
</body>
</html>
 
4.遍历次数:
plain 复制代码
 <!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<!--2.准备一个容器-->
<div id="root">
<!--       遍历固定次数  -->
    <ul>
        <!-- (item 次数,index 下标) -->
        <li v-for="(item,index)  in 5" :key="index">
            {{index}}-{{item}}
        </li>
    </ul>
</div>
<!--1.引入Vue js 文件-->
<script src="vue/vue.js"></script>
<script type="text/javascript">
    //3.创建Vue对象
    let vm = new Vue({
        data() {
            return {
            
             }
        }
    }).$mount("#root");
</script>
</body>
</html>
   

4.key的原理:

1.案例:
plain 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<!--2.准备一个容器-->
<div id="root">
    <h2>人员列表</h2>
    <button @click="add">添加老刘到列表中</button>
    <ul>
        <li v-for="(item,index)  in persons" :key="index">
            {{index}}-{{item.name}}-{{item.age}}
            <input type="text"/>
        </li>
    </ul>
</div>
<!--1.引入Vue js 文件-->
<script src="vue/vue.js"></script>
<script type="text/javascript">
    //3.创建Vue对象
    let vm = new Vue({
        data() {
            return {
                persons: [
                    {id: '001', name: '张三', age: 20},
                    {id: '002', name: '李四', age: 22},
                    {id: '003', name: '王武 ', age: 18}
                ]
            }
        },
        methods: {
            add() {
    
                 this.persons.unshift({id: '004', name: '老刘 ', age: 25}) //插入到第一个元素位置
               
            }
        }
    }).$mount("#root");
</script>
</body>
</html>
  

上面案例中我们给按钮绑定了一个事件,当事件触发时,会添加老刘的信息到对象数组中,再通过v-for指令来遍历对象数组,此时的key为下标index

点击按钮,触发事件,将老刘添加到首位

通过结果看,似乎没有问题,但当前面数据后面的文本框内有内容时,还会一一对应吗

复制代码
从测试结果来看,出现了数据错乱的现象。例如,新添加 "老刘" 到首位后,本应在其后的输入框为空,但却显示了原本张三对应的数据 "1"。

这种异常情况主要源于在 `v-for` 遍历时使用 `index` 作为 `key`。在该案例中,输入框内容与 `key`(即 `index`)存在绑定关系。初始时,数据 "1" 对应的 `index` 为 0,代表张三。然而,当 "老刘" 添加至首位后,`index` 为 0 的位置被 "老刘" 占据,导致数据与 `index` 的对应关系错乱,从而引发了上述显示错误。

实际上,从虚拟 DOM 的角度深入分析,在理想情况下,仅新增 "老刘" 这一数据时,其余数据未发生实质性改变,不应重新生成新的虚拟 DOM 对象。但由于 Vue 依靠 `key` 来判断节点身份,在新增数据到数组首位时,其余数据的下标发生改变,也就意味着以 `index` 作为 `key` 时其值发生了变化。此时,Vue 会判定这些节点均为新节点,进而生成新的虚拟 DOM 对象。这不仅会导致如输入框数据错乱等显示问题,而且即使不考虑数据错乱,这种因 `key` 变化而频繁生成新虚拟 DOM 对象的情况,会显著增加 Diff 算法的计算量以及真实 DOM 的更新操作次数。因为每次生成新虚拟 DOM 后,都需要与旧虚拟 DOM 进行全面的差异比对,然后根据比对结果更新真实 DOM,大量不必要的操作严重降低了 Vue 的执行效率。

综上所述,在使用 `v-for` 指令遍历动态数据列表时,强烈建议使用具有唯一性且稳定不变的属性作为 `key`,避免使用 `index`,以确保数据与 DOM 节点的正确绑定以及 Vue 应用的高效运行。

所以如果将index作为key则不应该进行逆序操作,如下面案例2所示

plain 复制代码
 <!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<!--2.准备一个容器-->
<div id="root">
    <h2>人员列表</h2>
    <button @click="add">添加老刘到列表中</button>
    <ul>
        <li v-for="(item,index)  in persons" :key="index">
            {{index}}-{{item.name}}-{{item.age}}
            <input type="text"/>
        </li>
    </ul>
</div>
<!--1.引入Vue js 文件-->
<script src="vue/vue.js"></script>
<script type="text/javascript">
    //3.创建Vue对象
    let vm = new Vue({
        data() {
            return {
                persons: [
                    {id: '001', name: '张三', age: 20},
                    {id: '002', name: '李四', age: 22},
                    {id: '003', name: '王武 ', age: 18}
                ]
            }
        },
        methods: {
            add() {
    
                 this.persons.push({id: '004', name: '老刘 ', age: 25}) //插入到最后
               
            }
        }
    }).$mount("#root");
</script>
</body>
</html>
   

此时我们再添加老刘到最后,再看看数据是否错乱

复制代码
此时发现数据是一一对应的,没有发现错乱,这是因为我们添加数据到末尾,没有改变原数据的index,也就不会出现错乱,同时原数据也不会重新生成虚拟DOM对象,Vue的效率也会相对较高

那如果一定要逆序插入数据,但又不想出现上面的问题,那该如何实现呢。

要实现这个需求,此时v-for指令中的key就不能是index了,而应该是遍历的数据中的一个属性(最好是唯一属性),如下面案例3所示:
plain 复制代码
 <!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<!--2.准备一个容器-->
<div id="root">
    <h2>人员列表</h2>
    <button @click="add">添加老刘到列表中</button>
    <ul>
        <li v-for="(item,index)  in persons" :key="item.id">
            {{index}}-{{item.name}}-{{item.age}}
            <input type="text"/>
        </li>
    </ul>
</div>
<!--1.引入Vue js 文件-->
<script src="vue/vue.js"></script>
<script type="text/javascript">
    //3.创建Vue对象
    let vm = new Vue({
        data() {
            return {
                persons: [
                    {id: '001', name: '张三', age: 20},
                    {id: '002', name: '李四', age: 22},
                    {id: '003', name: '王武 ', age: 18}
                ]
            }
        },
        methods: {
            add() {
    
                 this.persons.unshift({id: '004', name: '老刘 ', age: 25}) //插入到第一个元素位置
               
            }
        }
    }).$mount("#root");
</script>
</body>
</html>
   

此时我们添加老刘到首位,再看看是否可以实现

通过测试结果可以看出,我们成功将老刘添加到了首位,并且数据没有出现错乱

在上面的案例中,我们是通过遍历元素的id为key,因此数据后面的输入框内容也是和数据id绑定在一起的,所以当我们添加老刘时,并不会改变其余元素的key,因此就可以成功将数据添加到首位,且不会造成数据错乱

2:总结:
key的作用:
1.虚拟DOM中key 的作用: key作为虚拟DOM的标识。
复制代码
 当数据发生改变时,VUE会根据【新的数据】生成【新的虚拟DOM】,随后与旧的虚拟DOM进行差异比对

         1.旧的虚拟DOM中找到了与新的虚拟DOM相同的 key	
  • 如果虚拟DOM中的内容没有改变则使用之前的虚拟DOM

  • 如果虚拟DOM中的内容改变了,生成新的虚拟DOM,再将虚拟DOM对应得真实DOM中发生改变的部分进行覆盖

    2.如果旧的虚拟DOM中没有找到与新的虚拟DOM相同的key,创建新的真实DOM 渲染到页面中

2.index能否作为key?
复制代码
   1.如果对数据进行了逆序的操作(破坏了顺序的操作),会产生没有必要的真实DOM更新

   2.如果对数据的操作没有破坏顺序,那么就可以使用index作为key
3.图示:
相关推荐
夏小花花1 分钟前
vue3 ref和reactive的区别和使用场景
前端·javascript·vue.js·typescript
老虎062712 分钟前
JavaWeb前端(HTML,CSS具体案例)
前端·css·html
Joker Zxc1 小时前
【前端基础】flex布局中使用`justify-content`后,最后一行的布局问题
前端·css
前端小巷子1 小时前
Vue 自定义指令
前端·vue.js·面试
加班是不可能的,除非双倍日工资10 小时前
css预编译器实现星空背景图
前端·css·vue3
草梅友仁12 小时前
草梅 Auth 1.4.0 发布与 ESLint v9 更新 | 2025 年第 33 周草梅周报
vue.js·github·nuxt.js
萌萌哒草头将军14 小时前
Oxc 最新 Transformer Alpha 功能速览! 🚀🚀🚀
前端·javascript·vue.js
武昌库里写JAVA14 小时前
JAVA面试汇总(四)JVM(一)
java·vue.js·spring boot·sql·学习
littleding15 小时前
Vue3之计算属性
前端·vue.js