Maison > interface Web > js tutoriel > le corps du texte

Comment comprendre le principe de la liaison bidirectionnelle des données vue

清浅
Libérer: 2022-01-12 15:09:17
original
88995 Les gens l'ont consulté

Le principe de liaison bidirectionnelle des données Vue est obtenu grâce au détournement de données combiné au modèle « éditeur-abonné ». Tout d'abord, les données sont surveillées, puis l'abonné est averti lorsque les propriétés surveillées changent. pour mettre à jour, si mis à jour, la fonction de mise à jour correspondante sera exécutée pour mettre à jour la vue.

Comment comprendre le principe de la liaison bidirectionnelle des données vue

Le principe de la liaison bidirectionnelle des données Vue est réalisé grâce au détournement de données combiné au modèle éditeur-abonné. Tout d'abord, les données sont surveillées, puis quand. Lorsque les propriétés surveillées changent, il est indiqué à l'abonné s'il doit être mis à jour. En cas de mise à jour, la fonction de mise à jour correspondante sera exécutée pour mettre à jour la vue

Comment comprendre le principe de la liaison bidirectionnelle des données vue

[Cours recommandé : Tutoriel Vue]

Mode MVC

Le mode MVC précédent était une liaison unidirectionnelle, c'est-à-dire le modèle était lié à la vue Lorsque nous mettons à jour le modèle avec le code JavaScript, la vue sera automatiquement mise à jour

Comment comprendre le principe de la liaison bidirectionnelle des données vue

Mode MVVM

MVVM. Le mode est le mode Modèle – Vue – ViewModel. Il se rend compte que les modifications apportées à View sont automatiquement reflétées dans ViewModel et vice versa. La compréhension de la liaison bidirectionnelle est que lorsque l'utilisateur met à jour la vue, les données du modèle sont automatiquement mises à jour. Il s'agit d'une situation de liaison bidirectionnelle. Pour être plus détaillé, sur la base d'une liaison unidirectionnelle, un événement de changement (input) est ajouté aux éléments d'entrée input, textare, etc. (l'événement de changement est déclenché et l'état de la vue est mis à jour) pour dynamiquement modifier le modèle.

Comment comprendre le principe de la liaison bidirectionnelle des données vue

Principe de liaison bidirectionnelle

La liaison bidirectionnelle des données Vue s'effectue par détournement de données combiné au modèle éditeur-abonné. Implémenté

Nous savons déjà que pour implémenter la liaison bidirectionnelle des données, nous devons d'abord détourner et surveiller les données, nous devons donc configurer un observateur pour surveiller toutes les propriétés. Si l'attribut change, vous devez indiquer à l'abonné Watcher pour voir s'il doit être mis à jour. Parce qu'il y a de nombreux abonnés, nous avons besoin d'un service d'abonnés aux messages pour collecter spécifiquement ces abonnés, puis les gérer de manière uniforme entre l'Observateur et l'Observateur. Ensuite, nous avons également besoin d'un analyseur d'instructions Compile pour analyser et analyser chaque élément de nœud, initialiser les instructions pertinentes (telles que v-model, v-on) dans un observateur d'abonné et remplacer les données du modèle ou les lier à la fonction correspondante, lorsque le l'abonné Watcher reçoit la modification de l'attribut correspondant, il exécutera la fonction de mise à jour correspondante pour mettre à jour la vue.

Nous effectuons ensuite les 3 étapes suivantes pour obtenir une liaison bidirectionnelle des données :

(1) Implémentez un observateur d'écoute pour détourner et surveiller tous les attributs. S'il y a des changements, informez les abonnés. .

(2) Implémentez un observateur abonné. Chaque observateur est lié à une fonction de mise à jour. L'observateur peut recevoir des notifications de changement de propriété et exécuter les fonctions correspondantes pour mettre à jour la vue.

(3) Implémentez un analyseur Compile qui peut analyser et analyser les instructions pertinentes de chaque nœud (v-model, v-on et autres instructions si le nœud a v-model, v-on et autres). instructions, L'analyseur Compile initialise les données du modèle de ce type de nœud afin qu'elles puissent être affichées sur la vue, puis initialise l'abonné correspondant (Watcher).

Comment comprendre le principe de la liaison bidirectionnelle des données vue

Implémentation d'un observateur

Observer est un écouteur de données et sa méthode d'implémentation principale est Object.defineProperty(). Si vous souhaitez surveiller toutes les propriétés, vous pouvez parcourir toutes les valeurs de propriété​​par récursion et les traiter avec Object.defineProperty()
Le code suivant implémente un observateur.

function Observer(data) {    this.data = data;    this.walk(data);
}

Observer.prototype = {    walk: function(data) {        
var self = this;        //这里是通过对一个对象进行遍历,对这个对象的所有属性都进行监听
 Object.keys(data).forEach(function(key) {
       self.defineReactive(data, key, data[key]);
        });
    },    defineReactive: function(data, key, val) {        
    var dep = new Dep();      // 递归遍历所有子属性
        var childObj = observe(val);        
        Object.defineProperty(data, key, {            
        enumerable: true,            
        configurable: true,            
        get: function getter () {                
        if (Dep.target) {                  
        // 在这里添加一个订阅者
                  console.log(Dep.target)
                    dep.addSub(Dep.target);
                }                return val;
            },           
            // setter,如果对一个对象属性值改变,就会触发setter中的dep.notify(),
            通知watcher(订阅者)数据变更,执行对应订阅者的更新函数,来更新视图。
            set: function setter (newVal) {                
            if (newVal === val) {                    
            return;
                }
                val = newVal;              
                // 新的值是object的话,进行监听
                childObj = observe(newVal);
                dep.notify();
            }
        });
    }
};function observe(value, vm) {    if (!value || typeof value !== 'object') {        
return;
    }    return new Observer(value);
};// 消息订阅器Dep,订阅器Dep主要负责收集订阅者,然后在属性变化的时候执行对应订阅者的更新函数
function Dep () {    
this.subs = [];
}
Dep.prototype = {  /**
   * [订阅器添加订阅者]
   * @param  {[Watcher]} sub [订阅者]
   */
    addSub: function(sub) {        
    this.subs.push(sub);
    },  // 通知订阅者数据变更
    notify: function() {        
    this.subs.forEach(function(sub) {
            sub.update();
        });
    }
};
Dep.target = null;
Copier après la connexion

Dans Observer, quand j'ai regardé le code source d'autres personnes, une chose que je n'ai pas comprise, c'est d'où Dep.target venait. Je pense que certaines personnes auront les mêmes doutes que moi. Ne vous inquiétez pas ici. Lorsque vous écrivez sur Watcher, vous constaterez que ceci Dep.target vient de Watcher.

Implémentation d'un Watcher

Watcher est abonné. Utilisé pour traiter le message de mise à jour envoyé par l'Observer et exécuter la fonction de mise à jour liée au Watcher.

Le code suivant implémente un Watcher

function Watcher(vm, exp, cb) {    
this.cb = cb;    
this.vm = vm;    
this.exp = exp;    
this.value = this.get();  // 将自己添加到订阅器的操作}

Watcher.prototype = {    update: function() {        
this.run();
    },    run: function() {        
    var value = this.vm.data[this.exp];        
    var oldVal = this.value;        
    if (value !== oldVal) {            
    this.value = value;            
    this.cb.call(this.vm, value, oldVal);
        }
    },    get: function() {
        Dep.target = this;  // 缓存自己
        var value = this.vm.data[this.exp]  // 强制执行监听器里的get函数
        Dep.target = null;  // 释放自己
        return value;
    }
};
Copier après la connexion

Dans le processus d'étude du code, j'ai senti que le plus compliqué était de comprendre les paramètres de ces fonctions plus tard, après ma sortie. ces paramètres, ces fonctions de fonctions sont également faciles à comprendre. vm est l'objet SelfValue qui sera écrit plus tard, ce qui équivaut à un objet du nouveau Vue dans Vue. exp est la valeur d'attribut du modèle v du nœud ou v-on:click et d'autres instructions.

Comme vous pouvez le voir dans le code ci-dessus, dans la fonction getter de Watcher, Dep.target pointe vers lui-même, qui est l'objet Watcher. Dans la fonction getter,

var value = this.vm.data[this.exp]  // 强制执行监听器里的get函数。
这里获取vm.data[this.exp] 时,会调用Observer中Object.defineProperty中的get函数
get: function getter () {                
if (Dep.target) {                  
// 在这里添加一个订阅者                  
console.log(Dep.target)                    
dep.addSub(Dep.target);                
}                
return val;            
},
Copier après la connexion

ajoute ainsi l'observateur à l'abonné, ce qui résout le problème de savoir d'où vient ce Dep.target ci-dessus.

Implémenter une compilation

Compile主要的作用是把new SelfVue 绑定的dom节点,(也就是el标签绑定的id)遍历该节点的所有子节点,找出其中所有的v-指令和" {{}} ".
(1)如果子节点含有v-指令,即是元素节点,则对这个元素添加监听事件。(如果是v-on,则node.addEventListener('click'),如果是v-model,则node.addEventListener('input'))。接着初始化模板元素,创建一个Watcher绑定这个元素节点。

(2)如果子节点是文本节点,即" {{ data }} ",则用正则表达式取出" {{ data }} "中的data,然后var initText = this.vm[exp],用initText去替代其中的data。

实现一个MVVM

可以说MVVM是Observer,Compile以及Watcher的“boss”了,他需要安排给Observer,Compile以及Watche做的事情如下

(1)Observer实现对MVVM自身model数据劫持,监听数据的属性变更,并在变动时进行notify
(2)Compile实现指令解析,初始化视图,并订阅数据变化,绑定好更新函数
(3)Watcher一方面接收Observer通过dep传递过来的数据变化,一方面通知Compile进行view update。
最后,把这个MVVM抽象出来,就是vue中Vue的构造函数了,可以构造出一个vue实例。

最后写一个html测试一下我们的功能

<!DOCTYPE html><html lang="en"><head>
    <meta charset="UTF-8">
    <title>self-vue</title></head><style>
    #app {        
    text-align: center;
    }</style><body>
    <div id="app">
        <h2>{{title}}</h2>
        <input v-model="name">
        <h1>{{name}}</h1>
        <button v-on:click="clickMe">click me!</button>
    </div></body><script src="js/observer.js"></script>
    <script src="js/watcher.js"></script>
    <script src="js/compile.js"></script>
    <script src="js/mvvm.js"></script>
    <script type="text/javascript">
     var app = new SelfVue({        
     el: &#39;#app&#39;,        
     data: {            
     title: &#39;hello world&#39;,            
     name: &#39;canfoo&#39;
        },        
        methods: {            
        clickMe: function () {                
        this.title = &#39;hello world&#39;;
            }
        },        
        mounted: function () {            
        window.setTimeout(() => {                
        this.title = &#39;你好&#39;;
            }, 1000);
        }
    });</script></html>
Copier après la connexion

先执行mvvm中的new SelfVue(...),在mvvm.js中,

observe(this.data);
new Compile(options.el, this);
Copier après la connexion

先初始化一个监听器Observer,用于监听该对象data属性的值。
然后初始化一个解析器Compile,绑定这个节点,并解析其中的v-," {{}} "指令,(每一个指令对应一个Watcher)并初始化模板数据以及初始化相应的订阅者,并把订阅者添加到订阅器中(Dep)。这样就实现双向绑定了。
如果v-model绑定的元素,

<input v-model="name">
Copier après la connexion

即输入框的值发生变化,就会触发Compile中的

node.addEventListener(&#39;input&#39;, function(e) {            
var newValue = e.target.value;            
if (val === newValue) {                
return;
            }            
            self.vm[exp] = newValue;
            val = newValue;
        });
Copier après la connexion

self.vm[exp] = newValue;这个语句会触发mvvm中SelfValue的setter,以及触发Observer对该对象name属性的监听,即Observer中的Object.defineProperty()中的setter。setter中有通知订阅者的函数dep.notify,Watcher收到通知后就会执行绑定的更新函数。
最后的最后就是效果图啦:

Comment comprendre le principe de la liaison bidirectionnelle des données vue

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
À propos de nous Clause de non-responsabilité Sitemap
Site Web PHP chinois:Formation PHP en ligne sur le bien-être public,Aidez les apprenants PHP à grandir rapidement!