vue原始碼分析(二)>>:watch
阿新 • • 發佈:2020-08-27
今天來分析一下watch原始碼實現方式,watch就是實現某個屬性發生變化立即得到通知。
step1:watch用法:
基本用法如下(寫的比較粗糙,看不明白的看這篇基礎點的:https://www.cnblogs.com/rainbowLover/p/13036284.html):
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>vue-watch</title> </head> <body> <div id="app"> <p>info.name-{{info.name}}</p> <p>info.age-{{info.age}}</p> <p>hoppy-{{hobby}}</p> <p>tip-{{tip}}</p> <button @click="handleClick">click</button> </div> <script src="../../dist/vue.min.js"></script> <script> let vm = new Vue({ el:'#app', data:{ info:{ name:'張三', age:22 }, hobby:'love', tip:'哈哈' }, mounted() { // 用Vue的$watch新增,引數一:監聽的屬性名,引數二:回撥,引數三:配置this.$watch('tip',this.tipChanged,{immediate:true}) }, methods: { handleClick(){ this.info.name = '李四' this.info.age = 66 this.hobby = 'make' this.tip = '呵呵' }, tipChanged(){ console.log("tip watch >>:", arguments); } }, watch: { hobby(){// 方法名就是監聽的屬性名 console.log("hobby watch >>:", arguments); }, 'info.name':function(){// 監聽info的屬性name console.log("info.name watch >>:", arguments); }, info:{// 監聽info immediate:true,// 立馬執行 頁面載入時候會執行一次回撥方法 deep:true,// 開啟深度監聽的話 info的屬性變化也會觸發回撥, handler:function(){// 回撥 console.log("info watch >>:", arguments); } } } }) </script> </body> </html>
step2:watch原始碼實現:
vue在例項化時候走_init()方法,在beforeCreate和created之間回撥用initState方法,繼續追蹤這個方法:這個方法是初始化資料相關的物件,在這個方法裡邊看到先後執行了:initProps、initMethods、initData、initComputed,最後執行initWatch方法。看看這個方法:
function initWatch (vm, watch) { for (var key in watch) { var handler = watch[key]; if (Array.isArray(handler)) { for (var i = 0; i < handler.length; i++) { createWatcher(vm, key, handler[i]); } } else { createWatcher(vm, key, handler); } } }
斷點看到watch是:就是介面上定義的watch裡邊的東西
這裡看到watch[key]還可以是陣列?然後我趕緊去試一下:改成這樣
發現hobby變化時候這兩個方法都執行了!然後繼續往下看:createWatcher
// 查詢發現 這個方法只被初始化watch過程呼叫
// 引數一:vue例項物件
// 引數二:key
// 引數三:定義的方法或者深度監聽等配置
// 引數四:深度監聽等配置 只有this.$watch()方法定義watch時候使用,
function createWatcher (
vm,
expOrFn,
handler,
options
) {
// 如果是物件 就是深度監聽那種定義方法 info的那個定義
if (isPlainObject(handler)) {
options = handler;
handler = handler.handler;
}
// 如果是字串 就去看看方法裡邊定義的該方法
if (typeof handler === 'string') {
handler = vm[handler];
}
// 呼叫$watch
return vm.$watch(expOrFn, handler, options)
}
通過這個方法,把不同方式定義的watch規範一下,找到回撥方法,然後繼續看$watch方法:
step3:watch觸發: