Vue为我们提供了很多高级特性,学习和掌握它们有助于提高你的代码水平。
一、watch进阶
从我们刚开始学习Vue的时候,对于侦听属性,都是简单地如下面一般使用:
watch:{ a(){ //doSomething } }
实际上,Vue对watch提供了很多进阶用法。
handler函数
以对象和handler函数的方式来定义一个监听属性,handler就是处理监听变动时的函数:
watch:{ a:{ handler:'doSomething' } }, methods:{ doSomething(){ //当 a 发生变化的时候,做些处理 } }
handler有啥用?是多此一举么?用途主要有两点:
1 将处理逻辑抽象出去了,以method的方式被复用
2 给定义下面两个重要属性留出了编写位置
deep属性
不知道你注意到了没有?
当watch的是一个Object类型的数据,如果这个对象内部的某个值发生了改变,并不会触发watch动作!
也就是说,watch默认情况下,不监测内部嵌套数据的变动。但是很多情况下,我们是需要监测的!
为解决这一问题,就要使用deep属性:
watch:{ obj:{ handler:'doSomething', deep:true } }, methods:{ doSomething(){ //当 obj 发生变化的时候,做些处理 } }
deep属性默认为false,也就是我们常用的watch模式。
immediate属性
watch 的handler函数通常情况下只有在监听的属性发生改变时才会触发。
但有些时候,我们希望在组件创建后,或者说watch被声明和绑定的时候,立刻执行一次handler函数,这就需要使用immediate属性了,它默认为false,改为true后,就会立刻执行handler。
watch:{ obj:{ handler:'doSomething', deep:true, immediate:true } }, methods:{ doSomething(){ //当 obj 发生变化的时候,做些处理 } }
同时执行多个方法
使用数组可以设置多项,形式包括字符串、函数、对象
watch: { // 你可以传入回调数组,它们会被逐一调用 a: [ 'handle1', function handle2 (val, oldVal) { /* ... */ }, { handler: function handle3 (val, oldVal) { /* ... */ }, /* ... */ } ], }
二、$event的不同表现
$event 是事件对象的特殊变量,在两种场景下,它有不同的意义,代表不同的对象。
1 在原生事件中表示事件本身。可以通过$event.target获得事件所在的DOM对象,再通过value进一步获取具体的值。
<template> <div> <input type="text" @input="inputHandler('hello', $event)" /> </div> </template> export default { methods: { inputHandler(msg, e) { console.log(e.target.value) } } }
2 而在父子组件通过自定义事件进行通信时,表示从子组件中传递出来的参数值
看下面的例子:
//blog-post组件的模板 <button v-on:click="$emit('enlarge-text', 0.1)"> Enlarge text </button>
在父级组件监听这个事件的时候,可以通过 $event 访问到blog-post子组件传递出来的0.1这个值:
<blog-post ... v-on:enlarge-text="postFontSize += $event" ></blog-post>
此时,$event的值就是0.1,而不是前面的事件对象。
三、异步更新队列
1 Vue 在更新 DOM 时是异步执行的。
2 只要侦听到数据变化,Vue 将开启一个队列,并缓冲在同一事件循环中发生的所有数据变更。
3 如果同一个 watcher 被多次触发,只会被推入到队列中一次。
这种在缓冲时去除重复数据对于避免不必要的计算和 DOM 操作是非常重要的。然后,在下一个的事件循环“tick”中,Vue 刷新队列并执行实际 (已去重的) 工作。Vue 在内部对异步队列尝试使用原生的 Promise.then、MutationObserver 和 setImmediate,如果执行环境不支持,则会采用 setTimeout(fn, 0) 代替。
例如,当你设置 vm.someData = 'new value',该组件不会立即重新渲染。当刷新队列时,组件会在下一个事件循环“tick”中更新。
多数情况我们不需要关心这个过程,但是如果你想基于更新后的 DOM 状态来做点什么,这就可能会有些棘手。
虽然 Vue.js 通常鼓励开发人员使用“数据驱动”的方式思考,避免直接接触 DOM,但是有时我们必须要这么做。为了在数据变化之后等待 Vue 完成更新 DOM,可以在数据变化之后立即使用 Vue.nextTick(callback)。
这样回调函数将在 DOM 更新完成后被调用。例如:
<div>{{message}}</div> var vm = new Vue({ el: '#example', data: { message: '123' } }) vm.message = 'new message' // 更改数据 vm.$el.textContent === 'new message' // false Vue.nextTick(function () { vm.$el.textContent === 'new message' // true })
在组件内使用 vm.$nextTick() 实例方法特别方便,因为它不需要全局 Vue,并且回调函数中的 this 将自动绑定到当前的 Vue 实例上:
因为 $nextTick() 返回一个 Promise 对象,所以你可以使用新的 ES2017 async/await 语法完成相同的事情: