03-深入了解vue指令
Posted Ultraman_agul
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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",深入理解作用域链