精通 Vue.js 系列实例教程 │ Vue 组件的数据监听
简介: 如果 Vue 组件的一个变量 num 会被频繁更新,并且当变量 num 每次被更新时,需要进行一系列耗时的操作,如访问远程服务器的资源,或者通过复杂耗时的运算更新那些依赖变量 num 的其他变量(如 result 变量)。在这种情况下,可以通过 Vue 框架的数据监听器 Watcher 实现对变量 num 的监听。
如果 Vue 组件的一个变量 num 会被频繁更新,并且当变量 num 每次被更新时,需要进行一系列耗时的操作,如访问远程服务器的资源,或者通过复杂耗时的运算更新那些依赖变量 num 的其他变量(如 result 变量)。在这种情况下,可以通过 Vue 框架的数据监听器 Watcher 实现对变量 num 的监听。Vue 的 watch 选项会通过 Watcher 监听数据。例程 1 的 mywatch.html 演示了 watch 选项的基本用法。
■ 例程 1 mywatch.html
在 mywatch.html 中,Vue 应用实例的 watch 选项中有一个 num()函数,负责监听 num 变量。当 num 变量被更新,Vue 的数据监听器就会调用这个 num()函数。
通过浏览器访问 mywatch.html,会得到如图 1 所示的网页。在网页的 num 变量的输入框输入新的数字,Vue 的数据监听器就会调用 num()函数,更新 result 变量的值。
1、用 Web Worker 执行数据监听中的异步操作
对于例程 1 的 mywatch.html,当用户在网页的 num 变量的输入框输入新的数字时,num()函数就会被 Vue 的数据监听器调用。num()函数会先调用 sleep(2000)方法睡眠 2 秒,通过这种睡眠的方式来模拟耗时的操作。
num()函数是由浏览器的负责执行 JavaScript 脚本的主线程来执行的。当主线程执行 sleep(2000)方法睡眠时,网页处于卡死状态,不能响应用户的任何操作。只有当主线程执行完 num()函数,重新更新了网页,网页才能继续响应用户的操作。
如果希望用户始终可以和网页进行顺畅地交互,不会出现网页卡死的情况,可以通过一个额外的线程异步执行耗时的操作。这里会利用 HTML5 中的 Web Worker 线程来执行耗时操作。
首先创建一个 longtask.js 文件(文件名可以任意取),参见例程 2,它的 onmessage 函数包含了 Worker 线程接收到主线程发送的数据时所执行的操作。
■ 例程 2 longtask.js
在 onmessage 函数中,event.data 表示主线程发送过来的 num 变量。postMessage(result)用于向主线程发送 result 变量。
例程 3 的 mywatch-async.html 会通过 Worker 线程执行耗时操作。
■ 例程 3 mywatch-async.html
在 num()函数中,浏览器的主线程先通过以下语句为 result 变量赋予一个临时取值:
接着主线程通过“new Worker('longtask.js')”语句创建了 Worker 线程。接下来执行以下语句注册用于监听接收数据的 onmessage()函数:
当主线程接收到 Worker 线程发送的数据时,就会执行 worker.onmessage()函数中的 this.result=event.data 语句,event.data 表示 Worker 线程发送的数据。
主线程接着向 Worker 线程发送 newNum 变量:
各个浏览器对 Web Worker 的支持程度不一样。如果在 Chrome 浏览器中访问本地的 mywatch-async.html,然后在网页的输入框修改 num 变量的值,浏览器会产生以下错误:
这是因为 Chrome 出于安全的原因,不允许使用本地的 Web Worker 线程。把该范例发布到了 JavaThinker.net 网站上,网址如下:
通过浏览器访问上述网址,就可以正常访问 mywatch-async.html。在网页的输入框修改 num 变量的值,网页不会卡死,主线程会先显示 result 变量的临时取值,参见图 2。过 2 秒后,主线程再显示由 Worker 线程运算得到的 result 变量。
■ 图 2 网页显示 result 变量的临时取值
图 3 展示了主线程和 Worker 线程的通信及交换数据的过程。
■ 图 3 主线程和 Worker 线程的通信以及交换数据的过程
从图 3 可以看出,当主线程通过 worker.postmessage(newNum)方法向 Worker 线程发送 newNum 变量,就会触发 Worker 线程执行 longtask.js 中的 onmessage()函数。当 Worker 线程通过 postmessage(result)方法向主线程发送 result 变量,就会触发主线程执行 worker.onmessage()函数。无论是主线程还是 Worker 线程,都可以通过 event.data 读取对方发送的数据。
2、在 watch 选项中调用方法
在 watch 选项中还可以调用方法。例如在例程 4 的 score.html 中,如果 score 变量被更新,Vue 的数据监听器就会调用 judge()方法。
■ 例程 4 score.html
下面对 judge()方法做一些修改,使它通过 JavaScript 语言的 setTimeout()函数执行异步操作。
以上 judge()方法先给 result 变量赋予了一个临时值“正在运算,请稍后...”,然后利用 setTimeout()函数设置了异步操作:过 2 秒后计算 result 变量的取值。judge()方法产生的运行效果是,网页上首先显示“正在运算,请稍后...”,过 2 秒后再显示 reuslt 变量的实际取值。
3、深度监听
默认情况下,当 Vue 的 watch 选项监听一个对象时,不会监听对象的属性的变化。如果希望监听对象的属性变化,可以在 watch 选项中把 deep 属性设为 true,这样就会支持深度监听。
在例程 5 的 student.html 中,Vue 的 watch 选项会监听 student 对象,由于 deep 属性设为 true,当 student.score 属性被更新,watch 选项中的 handler()函数也会被执行。
■ 例程 5 student.html
通过浏览器访问 student.html 网页,在输入框修改 student.score 属性的值,Vue 的数据监听器会调用 handler()函数,更新 result 变量。
当 Vue 的数据监听器深度监听一个对象时,不管对象的属性嵌套了多少层,只要属性发生变化,就会被监听。
4、立即监听
通过浏览器访问例程 5 的 student.html 时,会看到网页上一开始显示{{student.score}}的值为 98,而{{result}}的值为空。因为这时候 Vue 的数据监听器还没有监听到 student.score 属性的变化,因此不会调用 watch 选项中的 handler()函数。
在 Vue 组件的生命周期中,如果希望在它的初始化阶段,Vue 框架就会调用一次 watch 选项中的 handler()函数,为 result 变量赋值,那么可以把 watch 选项的 immediate 属性设为 true。
下面对 student.html 做如下修改,增加 immediate: true 语句。
再次通过浏览器访问 student.html,会看到网页上{{student.score}}的初始值为 98,{{result}}的初始值为“及格”。
版权声明: 本文为 InfoQ 作者【TiAmo】的原创文章。
原文链接:【http://xie.infoq.cn/article/f4ed59e01ad96d7cea639e237】。文章转载请联系作者。
评论