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); } }
É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 } }) }
É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()) } }
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() } }) }
É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) } }
É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() } }) }
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))
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;idefineReactive(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)
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
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!