Maison > interface Web > js tutoriel > Compréhension approfondie des principes de réactivité de vue.js

Compréhension approfondie des principes de réactivité de vue.js

不言
Libérer: 2018-10-20 16:45:03
avant
2483 Les gens l'ont consulté

Cet article vous apporte une compréhension approfondie du principe de réactivité de vue.js. Il a une certaine valeur de référence. Les amis dans le besoin peuvent s'y référer. .

J'ai été exposé à angularjs il y a longtemps, j'avais déjà compris qu'angularjs implémentait la surveillance des données et le rendu des mises à jour des pages via une vérification sale. Après cela, je suis entré en contact avec vue.js à cette époque, j'étais très curieux de savoir comment vue.js surveillait les mises à jour des données et restituait la page. Aujourd'hui, nous allons analyser étape par étape le principe de réactivité de vue.js et implémenter une démo simple.

Tout d’abord, comprenons quelques bases.

###Connaissances de base

Object.defineProperty

es5 a ajouté l'API Object.defineProperty, qui nous permet de définir des getters et des setters pour les propriétés des objets, ainsi nous. peut détourner l'acquisition de valeur par l'utilisateur et l'attribution d'attributs d'objet. Par exemple, le code suivant :

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);
Copier après la connexion

Nous avons détourné les opérations d'acquisition et d'affectation de valeur de obj[name] via Object.defineProperty, nous pouvons donc faire quelques astuces ici. Par exemple, nous pouvons utiliser obj[. name] se voit attribuer une valeur, l'opération de mise à jour de la page est déclenchée.

Modèle de publication-abonnement

Le modèle de publication-abonnement est un modèle de conception courant, dans lequel il existe deux rôles : éditeur et abonné. Plusieurs abonnés peuvent s'abonner à un événement du même éditeur. Lorsque l'événement se produit, l'éditeur informe tous les abonnés abonnés à l'événement. Regardons un exemple pour comprendre.

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(); // 通知订阅者事件发生,触发他们的更新函数
Copier après la connexion

Pratique pratique

Après avoir compris Object.defineProperty et le modèle de publication-abonnement, il n'est pas difficile pour nous de penser que vue.js est basé sur les deux ci-dessus pour mettre en œuvre la surveillance des données.

vue.js utilise d'abord Object.defineProperty pour détourner les getters et setters des données à surveiller Lorsque les propriétés des données sont attribuées/récupérées, vue.js peut les détecter et les gérer en conséquence.

Grâce au modèle d'abonnement-publication, nous pouvons créer un éditeur pour chaque propriété de l'objet. Lorsque d'autres abonnés dépendent de cette propriété, l'abonné sera ajouté à la file d'attente de l'éditeur. Grâce au détournement de données d'Object.defineProperty, lorsque le setter de la propriété est appelé, l'éditeur de la propriété informe tous les abonnés du contenu mis à jour.
Ensuite, implémentons-le (voir les commentaires pour plus de détails) :

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';
Copier après la connexion

Conclusion

De cette façon, une simple surveillance réactive des données est complétée. Bien sûr, il ne s'agit que d'une simple démo pour illustrer le principe de réactivité de vue.js. Le vrai code source de vue.js sera plus compliqué car de nombreuses autres logiques sont ajoutées.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Étiquettes associées:
source:csdn.net
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal