1、事件对象
- 语法:
<div @click=‘fn($event)’></div>
中,$event
为事件对象(固定写法) - 作用:记录事件相关的信息
比如下面的这个例子,我使用 $ event,当点击某个项的时候,打印输出事件源$event.target
。(这个颜色的变化,是我为了让结果更清晰)
<div id="demoSky">
<ul>
<li v-for="(item,index) in arr" @click="fun($event,item)" :class="item.bool?'changeColor':''">{{item.type}}</li>
</ul>
</div>
<script>
new Vue({
el: "#demoSky",
data: {
arr:[
{type:"游乐场",bool:false},
{type:"动物园",bool:false},
{type:"摩天楼",bool:false},
],
},
methods:{
fun(e,item){
console.log(e.target);//e.target 事件源
item.bool=!item.bool;
}
}
})
</script>
然后还需要注意一点:
Vue 对函数调用做了封装,加与不加括号的区别在于事件对象参数 event 的处理。
(1)不加括号时,函数第一个参数为 event;
(2)加了括号后,需要手动传入 $event 才能获得事件对象。
不加括号,说明只存引用,等用到的时候,再去找到执行。
《学习笔记:js里调用函数时,函数名带括号与不带括号的区别》:
https://blog.csdn.net/Miss_Audrey/article/details/54846893?utm_source=app
2、事件修饰符
- 概念:
v-on
指令提供了事件修饰符来处理DOM事件细节
(一)按键修饰符
- 主要有:
.up .down .ctrl .enter .space
- 语 法:
@click.修饰符='fn()'
,比如 @keydown.ctrl=“fun($event)”,意为只有按下Ctrl按键的时候被触发。
<div id="demoSky">
<input type="text" name="" id="" @keydown.space="fun($event)">
</div>
<script>
new Vue({
el: "#demoSky",
data: {},
methods:{
fun(e){
console.log("点击空格键:",e.target);
}
}
})
</script>
(二)【扩展】事件修饰符
- prevent:阻止事件的默认行为 (比如submit提交表单时)
- stop 修饰符:阻止事件冒泡 (常用)
- capture:与事件冒泡的方向相反,事件捕获由外到内
- self:只会触发自己范围内的事件,不包含子元素
- once:只会触发一次
- 注意:修饰符可以串联使用
如下面,父亲包着儿子节点,然后父亲和儿子节点都绑定了事件,当点击儿子时,根据冒泡机制,先执行儿子的处理函数,然后执行父亲的。
<div id="demoSky">
<div id="father" @click="fun('father')">父亲
<div id="son" @click="fun('son')">儿子</div>
</div>
</div>
<script>
new Vue({
el:"#demoSky",
data:{},
methods:{
fun(i){
console.log(i);
}
}
})
</script>
但现在我想点击哪个就只触发哪个,那么怎么做呢?大家应该想到了阻止事件冒泡这个方法。
原生JS的阻止冒泡使用的是:e.stopPropagation();
;但在vue里面,可以简单使用事件修饰符stop
来阻止事件冒泡。
修改事件绑定,给事件加上stop阻止冒泡修饰符:
<div id="son" @click.stop="fun('son')">儿子</div>
结果就是当点击儿子的时候,只打印了“son”。
3、计算属性
(一)为什么要用计算属性
直白来讲,让一条数据在view层不同的位置显示不同的形态,在视图模板内使用表达式感觉非常方便,但设计它们的初衷是用于简单运算。
当在模板中放入太多的处理逻辑,会让模板过重且难以维护,比如 <p>{{text.toUpperCase().substr(2,1)}}</p>
,一两个还好,如果全部的标签都这样来处理逻辑,代码可读性会变差,视图看起来也会特别复杂。
所以,可以把view层中的数据处理逻辑,放到计算属性中进行。
那么,使用计算属性的好处就显而易见了:可以使代码简洁,逻辑清晰。
另外,计算属性还有一个特别优秀的地方:节省能耗。因为如果它监控的数据没有改变,多次调用计算属性,会从缓存里面读取数据。
(二)计算属性的概念
顾名思义,首先它是一种属性,其次它有“计算”这个特殊性质。每次取得它的值得时候,它并不像普通属性那样直接返回结果,而是经过一系列的计算之后再返回结果。同时只要在它的当中里引用了 data 中的某个属性,当这个属性发生变化时,计算属性仿佛可以嗅探到这个变化,并自动重新执行。
(三)计算属性–语法
computed
是vue中与data同级的一个属性,然后记得最后一定要把结果return
出来。
computed: {
需要返回的数据-变量名: function () {
return 处理操作
}
}
(四)计算属性–使用
截取数据,并把数据转换成大写的小栗子。
<div id="demoSky">
<p>原始数据:{{text}}</p>
<p>截取数据:{{text.substr(3,7)}}---从第3个开始截取,截取7个字符</p>
<p>大写数据:{{text.substr(6,6).toUpperCase()}}</p>
------------------------------------计算属性-------------------------------<br>
<p>截取数据:{{textSub1}}</p>
<p>大写数据:{{textSub2}}</p>
</div>
<script>
new Vue({
el:"#demoSky",
data:{
text:"12345678abcd",
},
computed:{
textSub1(){
return this.text.substr(3,7);
},
textSub2(){
return this.text.substr(6,6).toUpperCase();
},
}
})
</script>
提个问题: 如果data中的变量名与computed中的变量名相同了的话,会怎样?
验证:在vue实例的模型数据data里面新增一条数据 textSub1:“textSub1”,查看页面上的变化。
发现data里的数据优先。
(五)计算属性VS方法
将计算属性跟我们在methods里写的方法进行对比,会发现他们所实现的功能很相似,都是处理逻辑。既然计算属性能完成的,方法也能完成,那么为什么还要使用计算属性?或者说,计算属性和方法有什么区别呢?
上面的例子也可以使用方法来完成:
<p>截取并大写数据:{{textSubFun1()}}</p>
// vue的methods属性里:
methods:{
textSubFun1(){
return this.text.toUpperCase().substr(2,2);
}
}
计算属性与方法的区别:
- 计算属性是基于依赖进行缓存的。计算属性只有在它的相关依赖发生改变时才会重新求值。
- 方法绑定的数据只要被调用,调一次,执行 一次;调n次,执行n次。
- 计算属性,调n次,不一定执行n次。
- 计算属性中,只有当它监控的属性发生了变化,它才会重新计算;否则,会直接从缓存里面读取数据。所以相对于方法,计算属性在特定场合下能节省资源性能。
4、侦听/监听 watch
watch
:可以监听模型数据,当模型数据改变的时候就会触发。
watch:{
监听的data数据(newval,oldval){
console.log(newval+"---"+oldval)
}
}
PS:watch初始化的时候不会运行,只有数据被改变之后才会运行。
(一)什么时候使用watch
当需要在数据变化时执行异步或开销较大的操作时,watch这个方式是最有用的。
(二)计算属性与侦听器watch的区别
当watch监听的值发生改变就会被调用,watch可以在数据变化时做一些异步处理或者开销大的操作。
而计算属性是计算依赖的值,当依赖的值发生改变才会触发。
5、虚拟 dom 与 diff 算法
(一)什么是虚拟DOM:
所谓的虚拟 dom,也就是我们常说的虚拟节点,它是通过JS的Object对象模拟DOM中的节点,然后再通过特定的render(渲染)方法将其渲染成真实的DOM的节点。
(一)为什么使用虚拟DOM
使用JQuery的时候,会大量操作DOM,那么DOM元素的变化自然会引起页面的回流或者重绘,页面的DOM重绘自然会导致页面性能下降。那么如何尽可能的去减少DOM的操作是框架需要考虑的一个重要问题!
(一)真实DOM和虚拟DOM的区别
- 虚拟DOM不会进行排版与重绘操作
- 真实DOM频繁排版与重绘的效率是相当低
- 虚拟DOM进行频繁修改,然后一次性比较并修改真实DOM中需要改的部分,最后并在真实DOM中进行排版与重绘,减少过多DOM节点排版与重绘损耗
- 虚拟DOM有效降低页面的重绘与排版,因为最后与真实DOM比较差异,可以只渲染局部
(一)DOM Diff
虚拟DOM,是一种为了尽可能减少页面DOM频繁操作DOM的方式,那么在虚拟DOM中,通过什么方式才能做到呢?
就是Diff算法。
(一)DOM Diff原理
逐步解析newdom的节点,找到它在olddom中的位置,如果找到了就移动对应的DOM元素,如果没找到说明是新增节点,则新建一个节点插入。遍历完成之后如果oldVdom中还有没处理过的节点,则说明这些节点在newVdom中被删除了,删除它们即可。
大师兄说: diff算法,同级比较和差异更新。同级比较就是DOM很少有跨层级移动;DOM的数据结构是一棵多叉树,同级比较将DOM更新所需要的时间复杂度从On3降到了O(n),这是一个巨幅的性能提升,尤其在处理复杂规模的DOM变换场景下有显著优势。差异更新,就是利用虚拟DOM,在变化的时候不直接更新,而是比较虚拟DOM的属性,只更新有差异的部分,减少回流。
综合练习:ToDoList 练习
要求:
1、实现 “添加新任务” 的功能
- 使用 v-model 指令对用户输入内容进行双向绑定
- 点击 “添加” 按钮,将输入的内容添加进任务数组
2、实现 “可勾选已完成任务” 的功能
- 使用 v-model 指令对任务的勾选状态进行记录
- 使用 v-bind 指令对任务进行 class 绑定
- 将已勾选的选项设置为置灰状态
3、实现顶部数量信息展示
- 任务总数为数组的长度
- 遍历数组,查看待办事项状态,计算 “未完成” 任务数量
- 点击 “完成” ,将删除所有已完成任务
4、实现 “任务编辑” 功能
- 在 HTML 结构中添加表单元素
- 使用 v-model 指令对用户输入内容进行双向绑定
- 通过 v-show 指令控制表单与span标签的显示与隐藏(或者用 v-if 与 f-else)
- 已完成任务不可进行修改
链接我的博客:Vue.js note3(指令混合练习todolist)中的第二个例子