詳解Vue 事件驅動和依賴追蹤,詳解vue事件追蹤

來源:互聯網
上載者:User

詳解Vue 事件驅動和依賴追蹤,詳解vue事件追蹤

之前關於 Vue 資料繫結原理的一點分析,最近需要回顧,就順便發到隨筆上了

在之前實現一個自己的Mvvm中,用 setter 來觀測model,將介面上所有的 viewModel 綁定到 model 上。 當model改變,更新所有的viewModel,將新值渲染到介面上 。同時監聽介面上通過v-model 綁定的所有 input,並通過 addEventListener事件將新值更新到 model 上,以此來完成雙向繫結 。

但是那段程式除了用來理解 defineProperty,其它一文不值。

  1. 沒有編譯節點 。
  2. 沒有處理運算式依賴 。

這裡我將解決運算式依賴這個問題,vue 模板的編譯我會在下一節介紹 。

為資料定義 getter & setter

class Observer { constructor(data) {  this._data = data;  this.walk(this._data); } walk(data) {  Object.keys(data).forEach((key) => { this.defineRective(data, key, data[key]) }) }; defineRective(vm, key, value) {  var self = this;  if (value && typeof value === "object") {   this.walk(value);  }  Object.defineProperty(vm, key, {   get: function() {    return value;   },   set: function(newVal) {    if (value != newVal) {     if (newVal && typeof newVal === "object") {      self.walk(newVal);     }     value = newVal;    }   }  }) }}module.exports = Observer;

這樣,就為每個屬性添加了 getter setter ,當屬性是一個對象,那麼就遞迴添加。

 一旦擷取屬性值或者為屬性賦值就會觸發 get set ,當觸發了 set,即model變化,就發行就緒一個訊息,通知所有viewModel 更新。

defineRective(vm, key, value) { // 將這個屬性的依賴運算式儲存在閉包中。 var dep = new Dep(); var self = this; if (value && typeof value === "object") {  this.walk(value); } Object.defineProperty(vm, key, {  get: function() {   return value;  },  set: function(newVal) {   if (value != newVal) {    if (newVal && typeof newVal === "object") {     self.walk(newVal);    }    value = newVal;    // 通知所有的 viewModel 更新    dep.notify();   }  } })}

那麼怎麼定義 Dep 呢??

class Dep { constructor() {  // 依賴列表  this.dependences = []; } // 添加依賴 addDep(watcher) {  if (watcher) {   this.dependences.push(watcher);  } } // 通知所有依賴更新 notify() {  this.dependences.forEach((watcher) => {   watcher.update();  }) }}module.exports = Dep;

這裡的每個依賴就是一個Watcher

看看如何定義 Watcher

這裡每一個 Watcher 都會有一個唯一的id號,它擁有一個運算式和一個回呼函數 。

比如 運算式 a +b ; 會在get 計算時 訪問 a b , 由於 JavaScript是單線程,任一時刻只有一處JavaScript代碼在執行, 用Dep.target 作為一個全域變數來表示當前 Watcher 的運算式,然後通過 compute 訪問 a b ,觸發 a b getter,在 getter 裡面將 Dep.target 添加為依賴 。

一旦 a b set 觸發,調用 update 函數,更新依賴的值 。

var uid = 0;class Watcher { constructor(viewModel, exp, callback) {  this.viewModel = viewModel;  this.id = uid++;  this.exp = exp;  this.callback = callback;  this.oldValue = "";  this.update(); } get() {  Dep.target = this;  var res = this.compute(this.viewModel, this.exp);  Dep.target = null;  return res; } update() {  var newValue = this.get();  if (this.oldValue === newValue) {   return;  }  // callback 裡進行Dom 的更新操作  this.callback(newValue, this.oldValue);  this.oldValue = newValue; } compute(viewModel, exp) {  var res = replaceWith(viewModel, exp);  return res; }}module.exports = Watcher;

由於當前運算式需要在 當前的model下面執行,所以 採用replaceWith 函數來代替 with 。

通過get 添加依賴

Object.defineProperty(vm, key, { get: function() {  var watcher = Dep.target;  if (watcher && !dep.dependences[watcher.id]) {   dep.addDep(watcher);  }  return value; }, set: function(newVal) {  if (value != newVal) {   if (newVal && typeof newVal === "object") {    self.walk(newVal);   }   value = newVal;   dep.notify();  } }})

這種添加依賴的方式實在太巧妙了 。

這裡我畫了一個圖來描述

最後通過一段代碼簡單測試一下

const Observer = require('./Observer.js');const Watcher = require('./watcher.js');var data = { a: 10, b: {  c: 5,  d: {   e: 20,  } }}var observe = new Observer(data);var watcher = new Watcher(data, "a+b.c", function(newValue, oldValue) { console.log("new value is " + newValue); console.log("oldValue is " + oldValue);});console.log("\r\n");console.log("a has changed to 50,then the expr should has value 55");data.a = 50;console.log("\r\n");console.log("b.c has changed to 50,then the expr should has value 122");data.b.c = 72;;console.log("\r\n");console.log("b.c has reseted an object,then the expr should has value 80");data.b = { c: 30 }

OK 大功告成

以上就是本文的全部內容,希望對大家的學習有所協助,也希望大家多多支援幫客之家。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.