03-深入了解vue指令

一、指令的深入学习

1.1 class类切换的对象写法
    <div id="box">
        <!-- 
            执行结果如下
            <div class="aa bb cc"></div> 
        -->
        <div :class="classObj"></div>
    </div>
    <script>
        var vm = new Vue({
            el:"#box",
            data:{
                classObj:{
                    aa:true,
                    bb:true,
                    cc:true
                }
            }
        })
    </script>

:class=“obj”:obj对象中值为true的属性都会解析class类名,除此之外,还可以动态修改属性值为false或true,当设置属性为false,该属性作为类会在class类中删除,反之为添加该类。

  • 以下动态添加一个新的属性。
vm.classObj.dd = true;

说明:vm.classObj.dd = true;这样的添加方式无效,因为此时的dd属性不被get和set方法拦截,vue无法将dd渲染到页面

在这里插入图片描述

要动态添加一个属性,并且同步渲染为页面class类,可以使用如下方式

Vue.set(vm.classObj,"dd",true)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-af4ZgVNU-1630466219654)(images/get和set已拦截属性.png)]

class中已渲染该类:

在这里插入图片描述

1.2 class类切换的数组写法
    <div id="box">
        <div :class="classArr"></div>
    </div>
    <script>
        var vm = new Vue({
            el:"#box",
            data:{
                classArr:["aa","bb","cc"]
            }
        })
    </script>

说明:数组写法如果要添加或删除一个类会比对象写法简单得多

vm.classArr.push("dd");

用以上代码直接给数组中添加一个元素,该元素会作为类名直接渲染到页面,删除一个类,使用数组删除方法即可

vm.classArr.splice(1,1);
1.3 style行内样式切换对象写法
    <div id="box">
        <div :style="styleObj">hello</div>
    </div>
    <script>
        var vm = new Vue({
            el:"#box",
            data:{
                styleObj:{
                    background:"red"
                }
            }
        })
    </script>

动态修改及添加样式

        //动态修改样式
        vm.styleObj.background = "blue";
        //动态添加样式
        Vue.set(vm.styleObj,"fontSize","30px");
1.4 style行内样式切换数组写法
    <div id="box">
        <div :style="styleArr">hello</div>
    </div>
    <script>
        var vm = new Vue({
            el:"#box",
            data:{
                styleArr:[{
                    backgroundColor:"blue"
                }]
            }
        })
        //动态添加样式
        vm.styleArr.push({border:"5px solid black"});
        //动态删除样式
        vm.styleArr.shift();
    </script>
  • 案例:点击切换背景
    <div id="box">
        <ul>
            <!-- 
                当前对应下标的元素添加active类,其它元素class为''
                current===index?'active':'' 
            -->
            <li v-for="(item,index) in list" :class="current===index?'active':''" @click="change(index)">
                {{item}}
            </li>
        </ul>
    </div>
    <script>
        var vm = new Vue({
            el:"#box",
            data:{
                list:["首页","商品","详情"],
                current:0
            },
            methods:{
                change(index){
                    this.current = index;//点击时保存当前点击元素对应的下标
                } 
            }
        });
    </script>
1.5 深入学习v-if
  • v-else:todoList为例
    <div id="box">
        <!-- 通过v-model绑定,更新数据 -->
        <input type="text" v-model="inData">
        <button @click="handleClick()">add</button>
        <div v-if="dataList.length === 0">待办事项空空如也</div>
        <!-- 如果if不成立,渲染下面的代码 -->
        <ul v-else>
            <!-- 根据dataList渲染li节点 -->
            <li v-for="(item,index) in dataList">
                {{item}}
                <!-- 每一个节点有一个按钮,用于删除当前li节点,事件中传递了当前li的索引,删除时根据索引删除 -->
                <button @click="handelDel(index)">Del</button>
            </li>
        </ul>
    </div>
   
  • v-else-if
    <div id="box">
        <ul>
            <li v-for="item in list">
                <span>{{item.goodName}}</span>|
                <span>{{item.price}}</span>|
                <span v-if="item.stats === 0">未付款</span>
                <span v-else-if="item.stats === 1">已下单</span>
                <span v-else-if="item.stats === 2">已发货</span>
            </li>
        </ul>
    </div>
    <script>
        var vm = new Vue({
            el:"#box",
            data:{
                list:[
                    {
                        goodName:"手机1",
                        price:"3000",
                        stats:0//未付款
                    },
                    {
                        goodName:"手机2",
                        price:"4000",
                        stats:1//已下单
                    },
                    {
                        goodName:"手机3",
                        price:"5000",
                        stats:2//已发货
                    },

                ]
            }
        })
    </script>
  • template包裹元素在v-if中的使用

    <template>元素是一个特殊的不可见的包裹元素,有时候用于页面中可以减少指令的使用,同时也不会破坏页面的结构

    如以下程序:

        <script>
            var vm = new Vue({
                el:"#box",
                data:{
                   flag:true
                }
            })
        </script>
    

    有上面的flag模版,现在有需求,当flag为true时页面渲染三个div,如下

    	<div id="box">
            <!-- 当flag为true时同时显示三个div -->
            <div v-if="flag">aaa</div>
            <div v-if="flag">bbb</div>
            <div v-if="flag">ccc</div>
        </div>
    

    上面v-if指令使用了三次,我们想办法只使用一个v-if来实现,如下:

        <div id="box">
            <!-- 三个div的外层再包裹一个div,使用一个v-if指令来实现 -->
            <div v-if="flag">
                <div>aaa</div>
                <div>bbb</div>
                <div>ccc</div>
            </div>
        </div>
    

    上面使用了一个外层div来包裹,于是减少了v-if指令的使用,但是这时的外层div将原来的结构破坏了。

    使用<template>这个不可见的包裹元素,来代替这个外层的div,这样一来,既不破坏原有结构,也减少了v-if的使用,如下

        <div id="box">
            <!-- 三个div的外层再包裹一个template,使用一个v-if指令来实现,也不会破坏原来的结构 -->
            <template v-if="flag">
                <div>aaa</div>
                <div>bbb</div>
                <div>ccc</div>
            </template>
        </div>
    
1.6 深入学习v-for
  • v-for: of

    of遍历与in遍历是一至的效果

    • 遍历方式与v-for:in遍历数组是一样的效果
        <div id="box">
            <ul>
                <li v-for="(item,index) of list">
                    {{item}} --- {{index}}
                </li>
            </ul>
        </div>
        <script>
            var vm = new Vue({
                el:"#box",
                data:{
                   list:["aa","bb","cc"]
                }
            })
        </script>
    
    • 遍历对象
      • in遍历对象
        <div id="box">
            <ul>
                <!-- 遍历数组 -->
                <li v-for="(item,index) of list">
                    {{item}} --- {{index}}
                </li>
            </ul>
            <ul>
                <!-- in遍历对象 -->
                <!-- <li v-for="(val,key,index) in obj">
                    {{val}} --- {{key}} --- {{index}}
                </li> -->
                <!-- of遍历对象 -->
                 <li v-for="(val,key,index) of obj">
                    {{val}} --- {{key}} --- {{index}}
                </li>
            </ul>
        </div>
        <script>
            var vm = new Vue({
                el:"#box",
                data:{
                   list:["aa","bb","cc"],
                   obj:{
                       name:"tom",
                       age:18,
                       phone:"110"
                   }
                }
            })
        </script>
    
    • 使用in或of遍历阿拉伯数字,结果从1开始输出
            <ul>
                <!-- in或of遍历阿拉伯数字 -->
                <!-- <li v-for="n in 10"> -->
                <li v-for="n of 10">
                    {{n}}
                </li>
            </ul>
    
    • key

      1)vue中节点的操作,主要采用的是虚拟 DOM(Virtual DOM) 算法

在这里插入图片描述

Virtual DOM 是什么?

Virtual DOM 其实就是一棵以 JavaScript 对象( VNode 节点)作为基础的树,用对象属性来描述节点,实际上它只是一层对真实 DOM 的抽象。最终可以通过一系列操作使这棵树映射到真实环境上。

简单来说,可以把Virtual DOM 理解为一个简单的JS对象,并且最少包含标签名( tag)、属性(attrs)和子元素对象( children)三个属性。不同的框架对这三个属性的命名会有点差别。

Virtual DOM 作用是什么?

虚拟DOM的最终目标是将虚拟节点渲染到视图上。但是如果直接使用虚拟节点覆盖旧节点的话,会有很多不必要的DOM操作。例如,一个ul标签下很多个li标签,其中只有一个li有变化,这种情况下如果使用新的ul去替代旧的ul,因为这些不必要的DOM操作而造成了性能上的浪费。

为了避免不必要的DOM操作,虚拟DOM在虚拟节点映射到视图的过程中,将虚拟节点与上一次渲染视图所使用的旧虚拟节点(oldVnode)做对比,找出真正需要更新的节点来进行DOM操作,从而避免操作其他无需改动的DOM。

其实虚拟DOM在Vue.js主要做了两件事:

- 提供与真实DOM节点所对应的虚拟节点vnode
- 将虚拟节点vnode和旧虚拟节点oldVnode进行对比,然后更新视图
为何需要Virtual DOM?
  • 具备跨平台的优势

由于 Virtual DOM 是以 JavaScript 对象为基础而不依赖真实平台环境,所以使它具有了跨平台的能力,比如说浏览器平台、Weex、Node 等。

  • 操作 DOM 慢,js运行效率高。我们可以将DOM对比操作放在JS层,提高效率。

因为DOM操作的执行速度远不如Javascript的运算速度快,因此,把大量的DOM操作搬运到Javascript中,运用patching算法来计算出真正需要更新的节点,最大限度地减少DOM操作,从而显著提高性能。

Virtual DOM 本质上就是在 JS 和 DOM 之间做了一个缓存。可以类比 CPU 和硬盘,既然硬盘这么慢,我们就在它们之间加个缓存:既然 DOM 这么慢,我们就在它们 JS 和 DOM 之间加个缓存。CPU(JS)只操作内存(Virtual DOM),最后的时候再把变更写入硬盘(DOM)

  • 提升渲染性能

Virtual DOM的优势不在于单次的操作,而是在大量、频繁的数据更新下,能够对视图进行合理、高效的更新。

2),vue 会尽可能高效地渲染元素,通常会复用已有元素而不是从头开始渲染, 因此使用key值可以提高渲染效率,同理,改变某一元素的key值会使该元素重新被渲染。

3),遍历时,用于跟踪每一个遍历的节点的身份,从而重用和重新排序现有的元素,大大提供节点更新的效率

理想的key值设置,是每一项都有的且表示唯一 的id
 <div id="box">
     <ul>
         <li v-for="item in list" :key="item.id">
             <span>{{item.goodName}}</span>|
             <span>{{item.price}}</span>|
             <span v-if="item.stats === 0">未付款</span>
             <span v-else-if="item.stats === 1">已下单</span>
             <span v-else-if="item.stats === 2">已发货</span>
         </li>
     </ul>
 </div>
 <script>
     var vm = new Vue({
         el:"#box",
         data:{
             list:[
                 {
                     id:001,
                     goodName:"手机1",
                     price:"3000",
                     stats:0//未付款
                 },
                 {
                     id:002,
                     goodName:"手机2",
                     price:"4000",
                     stats:1//已下单
                 },
                 {
                     id:003,
                     goodName:"手机3",
                     price:"5000",
                     stats:2//已发货
                 },

             ]
         }
     })
 </script>
1.7 数组检测
  • 使用如下数组方法操作数组,vue会检测到数组的更新,使得页面重新渲染

    • push(),pop(),shift(),unshift(),splice(),sort(),reverse()
  • 使用如下数组方法操作数组,由于原数组不会发生改变,vue无法检测到数组的更新,页面不会重新渲染

    • filter(),concat(),slice(),map()

    • 解决办法:

      vm.dataList = vm.dataList.concat(["xxx","ccc"]);//通过重新赋值的方式将原数组改变
      
  • vm.dataList[1] = “xxx”:这样的方式修改数组的元素,vue也无法检测到数组的改变,原因在于,vue中的get和set方法无法对索引进行拦截

    • 解决办法:

      Vue.set(vm.dataList,2,"xx")
      

      或:

      vm.dataList.splice(2,1,"xx");
      

    【提示】以上vue无法检测数组更新的情况,是因为vue2.0采用Object.defineProperty拦截的原理来实现的。3.0后作了修正。

  • 使用事件实现列表过滤应用案例

<div id="box">
     <input type="text" @input="handleInput">
     <ul>
         <li v-for="item in list">
             {{item}}
         </li>
     </ul>
 </div>
 <script>
     var vm = new Vue({
         el:"#box",
         data:{
             list:["aaa","bbb","abc","bac","bbc","cbb","ccc"],
             //备份原始数据
             originList:["aaa","bbb","abc","bac","bbc","cbb","ccc"]
         },
         methods:{
             handleInput(eve){
                 //使用filter过滤备份的数组
                  var newArr = this.originList.filter(item=>item.includes(eve.target.value));
                  //过滤后的数据交给页面渲染的数组
                  this.list = newArr;
             }
         }
     })
 </script>
  • 使用函数表达式实现列表过滤应用案例
<div id="box">
    <!-- v-model实现双向数据绑定 -->
    <input type="text" v-model="myVal">
    <ul>
        <!-- 函数表达式返回过滤后的数组 -->
        <li v-for="item in updateData()">
            {{item}}
        </li>
    </ul>
</div>
<script>
    var vm = new Vue({
        el:"#box",
        data:{
            //绑定数据的模型
            myVal:"",
            list:["aaa","bbb","abc","bac","bbc","cbb","ccc"]
        },
        methods:{
            updateData(){
                //根据数据myVal的实时变化,返回过滤后的数组
                return this.list.filter(item=>item.includes(this.myVal));
            }
        }
    })
</script>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值