在
之前的文章《解析vue中observer資料雙向綁定原理(程式碼分享)》中,給大家了解了vue中observer資料雙向綁定原理。以下這篇文章給大家了解vue中watcher資料雙向綁定原理,一定的參考價值,有需要的朋友可以參考一下。
vue
資料雙向綁定原理,和簡單的實作,本文將實作mvvm
的 watcher
vue
資料雙向綁定原理,和簡單的實現,本文將實現mvvm
的Watcher
#上面的步驟已經實現了監聽器,和訂閱器,當屬性發生改變,發出通知,那麼這個通知是通知誰呢,肯定是訂閱者watcher
.Watcher
訂閱者作為Observer
和Compile
之間通信的橋樑,主要做的事情是:
1、在自身實例化時往屬性訂閱器(dep
)裡面加入自己
2、自身必須有一個update()
方法
3、待屬性變動dep.notice()
通知時,能呼叫自身的update()
方法,並觸發Compile
中綁定的回調,則釋放自己。
// Watcher function Watcher(vm, exp, cb) { this.cb = cb; this.$vm = vm; this.exp = exp; // 此处为了触发属性的getter,从而在dep添加自己,结合Observer更易理解 this.value = this.get(); // 将自己添加到订阅器的操作 } Watcher.prototype = { update: function () { this.run(); // 属性值变化收到通知 }, run: function () { var value = this.get(); // 取到最新值 var oldVal = this.value; if (value !== oldVal) { this.value = value; this.cb.call(this.$vm, value, oldVal); // 执行Compile中绑定的回调,更新视图 } }, get: function () { Dep.target = this; // 将当前订阅者指向自己, 缓存 var value = this.$vm[this.exp]; // 强制触发监听的getter,添加自己到属性订阅器中 Dep.target = null; // 添加完毕,重置释放 return value; }, };
訂閱者要快取自己,並且告訴監聽器,要把我加到訂閱器裡面去。所以也要改造下監聽器
function defineReactive(data, key, val) { var dep = new Dep() observe(val); // 监听子属性 Object.defineProperty(data, key, { .... get: function() { // 由于需要在闭包内添加watcher,所以可以在Dep定义一个全局target属性,暂存watcher, 添加完移除 Dep.target && dep.addDep(Dep.target); return val; }, .... }); }
實例化Watcher
的時候,呼叫get()
方法,透過Dep.target=watcherInstance
標記訂閱者是目前watcher
實例,強行觸發屬性定義的getter
方法,getter
方法執行的時候,就會在屬性的訂閱器 dep
新增目前watcher
實例,以便在屬性值有變化的時候watcherInstance
就能收到更新通知。
MVVM
到這兒先將監聽器Observer
和監聽者Watcher
連起來,先模擬一些數據,實作簡單的資料綁定
<div id="name"></div> <script> function Vue(data, el, exp) { this.data = data; observe(data); el.innerHTML = this.data[exp]; // 初始化模板数据的值 new Watcher(this, exp, function (value) { el.innerHTML = value; }); return this; } var ele = document.querySelector("#name"); var vue = new Vue( { name: "hello world", }, ele, "name" ); setInterval(function () { vue.data.name = "chuchur " + new Date() * 1; }, 1000); </script>
這可以看到div
的和內容初始為hello world
,每隔一秒之後變換為chuchur
加上時間戳,雖然是實現了,但是與想像的還差很多。是vue.name
不是vue.data.name
,所以這裡需要為Vue
實例新增一個屬性代理的方法,使存取vm
的屬性代理為存取vm.data
的屬性,改造後的程式碼如下:
function Vue(options) { this.$options = options || {}; this.data = this.$options.data; // 属性代理,实现 vm.xxx -> vm.data.xxx var self = this; Object.keys(this.data).forEach(function(key) { self.proxy(key); // 绑定代理属性 }); observe(this.data, this); el.innerHTML = this.data[exp]; // 初始化模板数据的值 new Watcher(this, exp, function(value) { el.innerHTML = value; }); return this; } Vue.prototype = { proxy: function(key) { var self = this; Object.defineProperty(this, key, { enumerable: false, configurable: true, get: function proxyGetter() { return self.data[key]; }, set: function proxySetter(newVal) { self.data[key] = newVal; } }); } }
然後就可以透過vue.name
,直接改版模板的數據了,下一步就要實作解析器Complie
[完]
#推薦學習:vue.js教學
###############################################以上是一文了解vue中watcher資料雙向綁定原則(附程式碼)的詳細內容。更多資訊請關注PHP中文網其他相關文章!