Heim  >  Artikel  >  Web-Frontend  >  Vertiefendes Verständnis der Reaktionsfähigkeitsprinzipien von vue.j

Vertiefendes Verständnis der Reaktionsfähigkeitsprinzipien von vue.j

不言
不言nach vorne
2018-10-20 16:45:032414Durchsuche

Dieser Artikel vermittelt Ihnen ein tiefgreifendes Verständnis des Reaktionsfähigkeitsprinzips von vue.js. Ich hoffe, dass er Ihnen als Referenz dienen wird. .

Ich bin schon vor langer Zeit mit AngularJS in Kontakt gekommen. Damals habe ich bereits verstanden, dass AngularJS die Datenüberwachung und das Rendern von Seitenaktualisierungen durch Dirty Checking implementiert. Danach kam ich mit vue.js in Kontakt. Damals war ich sehr neugierig, wie vue.js Datenaktualisierungen überwacht und die Seite neu rendert. Heute werden wir das Prinzip der Reaktionsfähigkeit von vue.j Schritt für Schritt analysieren und eine einfache Demo implementieren.

Lassen Sie uns zunächst einige Grundlagen verstehen.

###Grundkenntnisse

Object.defineProperty

es5 hat die Object.defineProperty-API hinzugefügt, mit der wir Getter und Setter für Objekteigenschaften festlegen können kann die Werterfassung und Zuweisung von Objektattributen durch den Benutzer kapern. Zum Beispiel der folgende Code:

const obj = {
};

let val = 'cjg';                      //前端全栈学习交流群:866109386                  
Object.defineProperty(obj, 'name', { //面向想从事前端开发1到5年及以上工作经验的开发人员
  get() {                           // 帮助突破技术瓶颈,提升思维,欢迎大家进群交流。
    console.log('劫持了你的取值操作啦');
    return val;
  },
  set(newVal) {
    console.log('劫持了你的赋值操作啦');
    val = newVal;
  }
});
console.log(obj.name);
obj.name = 'cwc';
console.log(obj.name);

Wir haben die Werterfassungs- und Zuweisungsoperationen von obj[name] über Object.defineProperty gekapert, sodass wir hier einige Tricks anwenden können. Beispielsweise können wir obj[name] verwenden. Löst bei Zuweisung den Seitenaktualisierungsvorgang aus.

Publish-Subscribe-Muster

Publish-Subscribe-Muster ist ein gängiges Designmuster, in dem es zwei Rollen gibt: Herausgeber und Abonnent. Mehrere Abonnenten können ein Ereignis desselben Herausgebers abonnieren. Wenn das Ereignis eintritt, benachrichtigt der Herausgeber alle Abonnenten, die das Ereignis abonniert haben. Schauen wir uns zum Verständnis ein Beispiel an.

class Dep {             //前端全栈学习交流群:866109386                  
  constructor() {     //面向想从事前端开发1到5年及以上工作经验的开发人员
    this.subs = [];  // 帮助突破技术瓶颈,提升思维,欢迎大家进群交流。
  }
  // 增加订阅者
  addSub(sub) {
    if (this.subs.indexOf(sub) < 0) {
      this.subs.push(sub);
    }
  }
  // 通知订阅者
  notify() {
    this.subs.forEach((sub) => {
      sub.update();
    })
  }
}

const dep = new Dep();

const sub = {
  update() {
    console.log('sub1 update')
  }
}

const sub1 = {
  update() {
    console.log('sub2 update');
  }
}

dep.addSub(sub);
dep.addSub(sub1);
dep.notify(); // 通知订阅者事件发生,触发他们的更新函数

Praktische Übung

Nachdem wir Object.defineProperty und das Publish-Subscriber-Muster verstanden haben, fällt es uns nicht schwer zu glauben, dass vue.js implementiert ist basierend auf den beiden oben genannten Datenüberwachung.

vue.js verwendet zunächst Object.defineProperty, um die Getter und Setter der zu überwachenden Daten zu kapern. Wenn die Eigenschaften der Daten zugewiesen/abgerufen werden, kann vue.js diese erkennen und entsprechend verarbeiten.

Durch das Abonnement-Veröffentlichungsmodell können wir für jede Eigenschaft des Objekts einen Herausgeber erstellen. Wenn andere Abonnenten von dieser Eigenschaft abhängig sind, wird der Abonnent zur Warteschlange des Herausgebers hinzugefügt. Mithilfe der Datenentführung von Object.defineProperty benachrichtigt der Herausgeber der Eigenschaft alle Abonnenten über den aktualisierten Inhalt, wenn der Setter der Eigenschaft aufgerufen wird.
Als nächstes implementieren wir es (siehe Kommentare für Details):

class Observer {
  constructor(data) {
    // 如果不是对象,则返回
    if (!data || typeof data !== 'object') {
      return;
    }
    this.data = data;
    this.walk();
  }

  // 对传入的数据进行数据劫持
  walk() {
    for (let key in this.data) {
      this.defineReactive(this.data, key, this.data[key]);
    }
  }
  // 创建当前属性的一个发布实例,使用Object.defineProperty来对当前属性进行数据劫持。
  defineReactive(obj, key, val) {
    // 创建当前属性的发布者
    const dep = new Dep();
    /*
    * 递归对子属性的值进行数据劫持,比如说对以下数据
    * let data = {
    *   name: 'cjg',
    *   obj: {
    *     name: 'zht',//前端全栈学习交流群:866109386                  
    *     age: 22,  //面向想从事前端开发1到5年及以上工作经验的开发人员
    *     obj: {  // 帮助突破技术瓶颈,提升思维,欢迎大家进群交流。
    *       name: 'cjg',
    *       age: 22,
    *     }
    *   },
    * };
    * 我们先对data最外层的name和obj进行数据劫持,之后再对obj对象的子属性obj.name,obj.age, obj.obj进行数据劫持,层层递归下去,直到所有的数据都完成了数据劫持工作。
    */
    new Observer(val);
    Object.defineProperty(obj, key, {
      get() {
        // 若当前有对该属性的依赖项,则将其加入到发布者的订阅者队列里
        if (Dep.target) {
          dep.addSub(Dep.target);
        }
        return val;
      },
      set(newVal) {
        if (val === newVal) {
          return;
        }
        val = newVal;
        new Observer(newVal);
        dep.notify();
      }
    })
  }
}

// 发布者,将依赖该属性的watcher都加入subs数组,当该属性改变的时候,则调用所有依赖该属性的watcher的更新函数,触发更新。
class Dep {
  constructor() {
    this.subs = [];
  }

  addSub(sub) {
    if (this.subs.indexOf(sub) < 0) {
      this.subs.push(sub);
    }
  }

  notify() {
    this.subs.forEach((sub) => {
      sub.update();
    })
  }
}

Dep.target = null;

// 观察者
class Watcher {
  /**
   *Creates an instance of Watcher.
   * @param {*} vm
   * @param {*} keys
   * @param {*} updateCb
   * @memberof Watcher
   */
  constructor(vm, keys, updateCb) {
    this.vm = vm;
    this.keys = keys;
    this.updateCb = updateCb;
    this.value = null;
    this.get();
  }

  // 根据vm和keys获取到最新的观察值
  get() {
    Dep.target = this;
    const keys = this.keys.split('.');
    let value = this.vm;
    keys.forEach(_key => {
      value = value[_key];
    });
    this.value = value;
    Dep.target = null;
    return this.value;
  }

  update() {
    const oldValue = this.value;   // 前端全栈学习交流群:866109386
    const newValue = this.get();  // 面向想从事前端开发1到5年及以上工作经验的开发人员
    if (oldValue !== newValue) { // 帮助突破技术瓶颈,提升思维,欢迎大家进群交流。
      this.updateCb(oldValue, newValue);
    }
  }
}

let data = {
  name: 'cjg',
  obj: {
    name: 'zht',
  },
};

new Observer(data);
// 监听data对象的name属性,当data.name发现变化的时候,触发cb函数
new Watcher(data, 'name', (oldValue, newValue) => {
  console.log(oldValue, newValue);
})

data.name = 'zht';

// 监听data对象的obj.name属性,当data.obj.name发现变化的时候,触发cb函数
new Watcher(data, 'obj.name', (oldValue, newValue) => {
  console.log(oldValue, newValue);
})

data.obj.name = 'cwc';
data.obj.name = 'dmh';

Fazit

Auf diese Weise ist eine einfache reaktive Datenüberwachung abgeschlossen. Dies ist natürlich nur eine einfache Demo zur Veranschaulichung des Reaktionsfähigkeitsprinzips von vue.js. Der eigentliche Quellcode von vue.js wird komplizierter, da viele andere Logiken hinzugefügt werden.

Das obige ist der detaillierte Inhalt vonVertiefendes Verständnis der Reaktionsfähigkeitsprinzipien von vue.j. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:csdn.net. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen