原副标题:通晓Vue.js系列产品实例教程 │ Vue模块的统计数据窃听
假如Vue模块的两个表达式num会被频密预览,因此当表达式num每天被预览时,须要展开一连串产品费时的操作方式,如出访远距伺服器的天然资源,或是透过繁杂耗时的演算预览这些倚赖表达式num的其它表达式(如result表达式)。在此种情况下,能透过Vue架构的统计数据窃听器Watcher同时实现对表达式num的窃听。
Vue的watch快捷键会透过Watcher窃听统计数据。例程1的mywatch.html模拟了watch快捷键的基本上用语。
■解释器1 mywatch.html
< divid= “app”> < p> < inputv-model= “num”/> </ p> < p> {{ result }}</ p> </ div>< > constvm=Vue.createApp({ data{return{ num: 0, result: 0} },methods:{ //睡眠方法,参数numberMillis是睡眠的毫秒数sleep(numberMillis) { varnow = newDate; varexitTime = now.getTime + numberMillis while( true) { now =newDateif(now.getTime > exitTime) return; } }},watch: { //当num表达式被预览,就会调用此函数//newNum参数表示预览后的num表达式//oldNum参数表示预览前的num表达式num(newNum, oldNum) { //num表达式的窃听函数this.sleep( 2000) //睡眠2秒this.result= Math.sqrt(newNum) //计算平方根}}}).mount( #app) </ > </ body> </ html>
在mywatch.html中,Vue应用实例的watch快捷键中有两个num函数,负责窃听num表达式。当num表达式被预览,Vue的统计数据窃听器就会调用这个num函数。
透过浏览器出访mywatch.html,会得到如图1所示的网页。在网页的num表达式的输入框输入新的数字,Vue的统计数据窃听器就会调用num函数,预览result变量的值。
■图1 mywatch.html的网页
1
用Web Worker执行统计数据窃听中的异步操作方式
对于解释器1的mywatch.html,当用户在网页的num表达式的输入框输入新的数字时,num函数就会被Vue的统计数据窃听器调用。num函数会先调用sleep(2000)方法睡眠2秒,透过此种睡眠的方式来模拟费时的操作方式。
num函数是由浏览器的负责执行Java脚本的主线程来执行的。当主线程执行sleep(2000)方法睡眠时,网页处于卡死状态,不能响应用户的任何操作方式。只有当主线程执行完num函数,重新预览了网页,网页才能继续响应用户的操作方式。
假如希望用户始终能和网页展开顺畅地交互,不会出现网页卡死的情况,可以透过两个额外的线程异步执行费时的操作方式。这里会利用HTML5中的Web Worker线程来执行费时操作方式。
首先创建两个longtask.js文件(文件名能任意取),参见解释器2,它的onmessage函数包含了Worker线程接收到主线程发送的统计数据时所执行的操作方式。
■解释器2 longtask.js
//睡眠函数,参数numberMillis是睡眠的毫秒数functionsleep( numberMillis) {…}//当Worker线程接收到主线程发送的统计数据时,调用此函数onmessage= function( event) { varnum=event.data //读取主线程发送过来的统计数据sleep( 2000) //睡眠2秒,模拟费时的操作方式varresult= Math.sqrt(num) //求平方根postMessage(result) //向主线程发送演算结果 }
在onmessage函数中,event.data表示主线程发送过来的num表达式。postMessage(result)用于向主线程发送result表达式。
解释器3的mywatch-async.html会透过Worker线程执行费时操作方式。
■解释器3 mywatch-async.html
< divid= “app”> < p> < inputv-model= “num”/> </ p> < p> {{ result }} </ p> </ div>< > constvm=Vue.createApp({data{return{ num: 0, result: 0} } ,
watch: { // 当num表达式被预览,就会调用此方法num(newNum, oldNum) { // num表达式的窃听函数this.result= 正在演算,请稍后…//创建Worker线程 varworker= newWorker( longtask.js)
//注册窃听接收Worker线程发送统计数据的函数worker.onmessage=( event)=> this.result=event.data
//向Worker线程发送统计数据worker.postMessage(newNum) }}}).mount( #app) </ >
在num函数中,浏览器的主线程先透过以下语句为result表达式赋予两个临时取值:
this.result= 正在演算,请稍后…接着主线程透过“new Worker(longtask.js)”语句创建了Worker线程。接下来执行以下语句注册用于窃听接收统计数据的onmessage函数:
worker.onmessage= ( event)=> this.result=event.data当主线程接收到Worker线程发送的统计数据时,就会执行worker.onmessage函数中的this.result=event.data语句,event.data表示Worker线程发送的统计数据。
主线程接着向Worker线程发送newNum表达式:
worker.postMessage( newNum)各个浏览器对Web Worker的支持程度不一样。假如在Chrome浏览器中出访本地的mywatch-async.html,然后在网页的输入框修改num表达式的值,浏览器会产生以下错误:
Uncaught ( inpromise) DOMException: Failed to construct Worker: at file:///C:/vue/sourcecode/chapter03/longtask.jscannot be accessed fromorigin null.这是因为Chrome出于安全的原因,不允许使用本地的Web Worker线程。笔者把该范例发布到了JavaThinker.net网站上,网址如下:
www.javathinker.net/vue/mywatch- async.html透过浏览器出访上述网址,就能正常出访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
< divid= “app”> < p> < inputv-model= “score”/> </ p> < p> {{ result }} </ p> </ div>< > constvm=Vue.createApp({ data{return{ score: , result: } } ,
methods:{ judge { if( this.score>= 60) this.result= 及格elsethis.result= 不及格}},
watch: { score: judge//调用judge方法}}).mount( #app) </ >
下面对judge方法做一些修改,使它透过Java语言的setTimeout函数执行异步操作方式。
judge {this.result= “正在演算,请稍后…”setTimeout( =>{if( this.score>= 60) this.result= 及格elsethis.result= 不及格}, 2000)//延迟2秒后再执行演算}以上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
< divid= “app”> < p> < inputv-model= “student.score”/> </ p> < p> {{ result }} </ p> </ div>< > constvm=Vue.createApp({ data{return{ student: { name: Tom,score: 98} , result: }} ,
watch: { student: { //窃听student对象handler(newStudent,oldStudent){if( this.student.score>=60) this.result= 及格elsethis.result= 不及格},deep: true//启用深度窃听}}}).mount( #app) </ >
透过浏览器出访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语句。
watch: {student: { handler(newStudent,oldStudent){…}, immediate: true, deep: true}}再次透过浏览器出访student.html,会看到网页上{{student.score}}的初始值为98,{{result}}的初始值为“及格”。
5
参考书籍
点击上图看详细图书介绍
《通晓Vue.js:Web前端开发技术详解(微课视频版)》
详细阐述用Vue架构的各种技术;深刻揭示前端开发的响应式编程核心思想;介绍与其它流行技术的整合;典型范例帮助读者迅速获得实战经验。
作者:孙卫琴,杜聚宾
价格:119元
扫码优惠购书
实例讲解
通晓Vue.js:
Web前端开发技术详解
精彩回顾
1. Vue模块的命名规则
2 . 注册全局模块和局部模块
3 . 路由导航中抓取统计数据
4. 路由管理器的基本上用语
5. 命名路由
6. CSS中DOM元素的过渡模式
7. 插槽slot的基本上用语
8. 模块的递归
9. 在Vue项目中使用Axios
10. 自定义指令v-drag范例
11. Vuex中的异步操作方式
12. 分割setup函数
13. Vue模块的单向统计数据流