Maison > interface Web > js tutoriel > Comment implémenter la réactivité de vue2.0 (tutoriel détaillé)

Comment implémenter la réactivité de vue2.0 (tutoriel détaillé)

亚连
Libérer: 2018-06-05 17:48:44
original
1811 Les gens l'ont consulté

Cet article présente principalement les idées de base pour implémenter la réactivité de vue2.0. Maintenant, je le partage avec vous et vous donne une référence.

J'ai récemment lu le code source de vue2.0 sur l'implémentation de la réactivité. Le billet de blog suivant restaurera les idées d'implémentation de vue2.0 sur la réactivité via un code simple.

Notez qu'il ne s'agit que d'une restauration de l'idée d'implémentation. L'implémentation de divers détails, tels que la surveillance des opérations de données dans les tableaux et l'imbrication d'objets, ne sera pas abordée dans cet exemple. Pour une implémentation plus détaillée, vous pouvez en savoir plus en lisant le dossier de l'observateur du code source et le fichier d'état dans le dossier de l'instance.

Tout d'abord, définissons la structure de l'objet vue

class Vue {
  constructor(options) {
    this.$options = options;
    this._data = options.data;
    this.$el = document.querySelector(options.el);
  }
}
Copier après la connexion

Étape 1 : Changez les attributs sous data en observable

Utiliser l'objet. définirProperty pour surveiller les propriétés get et set de l'objet de données. Lorsqu'il y a des opérations de lecture et d'affectation de données, les instructions du nœud sont appelées de cette manière, l'affectation de signe = égal la plus courante peut être déclenchée.

//数据劫持,监控数据变化
function observer(value, cb){
 Object.keys(value).forEach((key) => defineReactive(value, key, value[key] , cb))
}

function defineReactive(obj, key, val, cb) {
 Object.defineProperty(obj, key, {
  enumerable: true,
  configurable: true,
  get: ()=>{
   return val
  },
  set: newVal => {
   if(newVal === val)
    return
   val = newVal
  }
 })
}
Copier après la connexion

Étape 2 : Implémenter un abonné au message

C'est très simple. Nous maintenons un tableau et mettons les abonnés dans ce tableau. Une fois la notification déclenchée, le. l'abonné appelle sa propre méthode de mise à jour

class Dep {
 constructor() {
  this.subs = []
 }
 add(watcher) {
  this.subs.push(watcher)
 }
 notify() {
  this.subs.forEach((watcher) => watcher.cb())
 }
}
Copier après la connexion

Chaque fois que la fonction set est appelée, nous déclenchons une notification pour implémenter la mise à jour

Ensuite, le problème survient. Qui sont les abonnés. Oui, c'est Watcher. . Une fois que dep.notify() traverse les abonnés, c'est-à-dire Watcher, et appelle sa méthode update()

function defineReactive(obj, key, val, cb) {
 const dep = new Dep()
 Object.defineProperty(obj, key, {
  enumerable: true,
  configurable: true,
  get: ()=>{
   return val
  },
  set: newVal => {
   if(newVal === val)
    return
   val = newVal
   dep.notify()
  }
 })
}
Copier après la connexion

Étape 3 : implémenter un Watcher

Le la mise en œuvre de Watcher est relativement simple. En fait, c'est l'opération que nous devons effectuer lorsque les données changent

class Watcher {
 constructor(vm, cb) {
  this.cb = cb
  this.vm = vm
 }
 update(){
  this.run()
 }
 run(){
  this.cb.call(this.vm)
 } 
}
Copier après la connexion

Étape 4 : toucher pour obtenir la dépendance

Dans les trois étapes ci-dessus, nous avons mis en œuvre le fait que les modifications de données peuvent déclencher des mises à jour, mais le problème est maintenant que nous ne pouvons pas associer l'observateur à nos données.

Nous savons qu'une fois que l'attribut sur data est défini sur definitionReactive, la modification de la valeur sur data déclenchera la définition. Ensuite, lorsque nous prendrons la valeur supérieure des données, get sera déclenché. Vous pouvez donc en profiter et exécuter d'abord la fonction de rendu suivante pour savoir quelle prise en charge des données est nécessaire pour mettre à jour la vue et l'enregistrer en tant qu'abonné aux données.

function defineReactive(obj, key, val, cb) {
 const dep = new Dep()
 Object.defineProperty(obj, key, {
  enumerable: true,
  configurable: true,
  get: ()=>{
   if(Dep.target){
    dep.add(Dep.target)
   }
   return val
  },
  set: newVal => {
   if(newVal === val)
    return
   val = newVal
   dep.notify()
  }
 })
}
Copier après la connexion

Enfin, regardons l'utilisation d'un proxy pour lier notre accès aux données à l'objet vue

 _proxy(key) {
  const self = this
  Object.defineProperty(self, key, {
   configurable: true,
   enumerable: true,
   get: function proxyGetter () {
    return self._data[key]
   },
   set: function proxySetter (val) {
    self._data[key] = val
   }
  })
}

Object.keys(options.data).forEach(key => this._proxy(key))
Copier après la connexion

Ce qui suit est le code complet de l'instance entière

class Vue {
 constructor(options) {
  this.$options = options;
  this._data = options.data;
  this.$el =document.querySelector(options.el);
  Object.keys(options.data).forEach(key => this._proxy(key))
  observer(options.data)
  watch(this, this._render.bind(this), this._update.bind(this))
 }
 _proxy(key) {
  const self = this
  Object.defineProperty(self, key, {
   configurable: true,
   enumerable: true,
   get: function proxyGetter () {
    return self._data[key]
   },
   set: function proxySetter (val) {
    self._data[key] = val
   }
  })
 }
 _update() {
  console.log("我需要更新");
  this._render.call(this)
 }
 _render() {
  this._bindText();
 }

 _bindText() {
  let textDOMs=this.$el.querySelectorAll('[v-text]'),
  bindText;
  for(let i=0;i defineReactive(value, key, value[key] , cb))
}

function defineReactive(obj, key, val, cb) {
 const dep = new Dep()
 Object.defineProperty(obj, key, {
  enumerable: true,
  configurable: true,
  get: ()=>{
   if(Dep.target){
    dep.add(Dep.target)
   }
   return val
  },
  set: newVal => {
   if(newVal === val)
    return
   val = newVal
   dep.notify()
  }
 })
}
function watch(vm, exp, cb){
 Dep.target = new Watcher(vm,cb);
 return exp()
}

 class Watcher {
 constructor(vm, cb) {
  this.cb = cb
  this.vm = vm
 }
 update(){
  this.run()
 }
 run(){
  this.cb.call(this.vm)
 } 
}

class Dep {
 constructor() {
  this.subs = []
 }
 add(watcher) {
  this.subs.push(watcher)
 }
 notify() {
  this.subs.forEach((watcher) => watcher.cb())
 }
}
Dep.target = null; 
var demo = new Vue({
 el: '#demo',
 data: {
 text: "hello world"
 }
 })
 
setTimeout(function(){
 demo.text = "hello new world"
 
}, 1000)

 
  

Copier après la connexion

Ce qui précède est l'idée générale de toute la partie basée sur les données de vue. Si vous souhaitez en savoir plus sur l'implémentation plus en détail, il est recommandé d'examiner de plus près cette partie du code de vue.

J'ai compilé ce qui précède pour vous, j'espère que cela vous sera utile à l'avenir.

Articles associés :

Utilisez vue+element-ui+ajax pour implémenter un exemple de table

Utiliser live -server Comment pour configurer un serveur local et actualiser automatiquement ? Quelles sont les méthodes spécifiques ?

Résoudre le problème selon lequel les navigateurs de version inférieure ne prennent pas en charge l'importation d'es6

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:php.cn
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