ホームページ > ウェブフロントエンド > jsチュートリアル > vue の応答性の原則と依存関係の収集の概要 (コード付き)

vue の応答性の原則と依存関係の収集の概要 (コード付き)

不言
リリース: 2019-03-26 10:15:29
転載
1664 人が閲覧しました

この記事では、Vue のレスポンシブ原則と依存関係コレクション (コード付き) を紹介します。これには一定の参考価値があります。必要な友人は参照できます。お役に立てれば幸いです。

Vue は、オブジェクト プロパティの setter/getter メソッドを設定することでデータの変更を監視し、getter を通じて依存関係を収集します。各 setter メソッドはオブザーバーであり、データが変更されたときにビューを更新するようにサブスクライバーに通知します。

データを観察可能なものに変える

それでは、Vue はどのようにしてデータ内のすべてのプロパティを観察可能なものに変えるのでしょうか?

function obsever(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=>{
            val=newVal;
            cb();
        }
    })
}
class Vue{
    constructor(options){
        this._data = options.data;
        obsever(this._data,options.render)
    }
}

let app = new Vue({
    el:'#app',
    data:{
        text:'text',
        text2:'text2'
    },
    render(){
        console.log('render')
    }
})
ログイン後にコピー

理解を容易にするために、配列などを考慮せずに、最も単純なケースを最初に考えます。コードは上記のとおりです。 initData では、observ 関数が呼び出され、Vue データが観察可能に設定されます。 _data データが変更されると、set がトリガーされ、サブスクライバー (この場合はレンダリング) にコールバックが行われます。
次に問題が発生します。app._data.text を操作してセットをトリガーする必要があります。怠惰にするには、app.text を通じてビューを直接設定することで、セットをトリガーしてビューを再描画する便利な方法が必要です。それからエージェントに行く必要があります。

プロキシ

Vue のコンストラクター コンストラクターでデータのプロキシ プロキシを実行できます。このようにして、データの属性を VM インスタンスにプロキシします。

_proxy.call(this,options.data);//构造函数
//代理
function _proxy(data){
    const that = this;
    Object.keys(data).forEach(key=>{
        configurable:true,
        enumerable:true,
        get:function proxyGetter(){
            return that._data[key]
        },
        set:function proxySetter(val){
            that._data[key] = val;
        }
    })
}
ログイン後にコピー

app._data.text の代わりに app.text を使用できます。

なぜコレクションに依存する必要があるのか​​

まず次のコードを見てください

new Vue({
    template:`<p>
                <span>text1:</span>{{text1}}
                <span>text2:</span>{{tetx2}}
              </p>`,
    data:{
        text1:'text1',
        text2:'text2',
        text3:'text3'
    }
})
ログイン後にコピー

レスポンシブ原則のメソッドに従ってバインドする場合問題の 1 つは、実際のテンプレートでは text3 が使用されていないことです。しかし、text3 のデータが変更されると、text3 のセッターもトリガーされ、レンダリングが再実行されます。これは明らかに間違っています。 。

Dep について話しましょう

データ上のオブジェクトの値が変更されると、そのセッターがトリガーされ、値が取得されるとゲッター イベントがトリガーされますしたがって、最初にレンダリングを実行する限り、レンダリングが依存するデータ内のすべてのデータがゲッターによって Dep のサブに収集されます。 data 内のデータを変更する場合、setter は Dep の subs 関数のみをトリガーします。
コレクション クラスに依存する Dep を定義します。

class Dep{
    constructor(){
        this.subs = [];
    }
    addSub(sub:Watcher){
        this.subs.push(sub)
    }
    removeSub(sub:Watcher){
        remove(this.subs,sub)
    }
    notify(){
        const subs = this.subs.slice()
        for(let i = 0;l=subs.length;i<1;i++){
            subs[i].update()
        }
    }
}
function remove(arr,item){
    if(arr.length){
        const index = arr.indexOf(item)
        if(index>-1){
            return arr.splice(index,1)
        }
    }
}
ログイン後にコピー

Watcher

サブスクライバーは、依存関係が収集されると、サブにサブを追加します。データ内のデータが変更されると、dep オブジェクトの通知がトリガーされます。すべての Watcher オブジェクトに、対応するビューを変更するように通知します。

class Watcher {
    constructor (vm, expOrFn, cb, options) {
        this.cb = cb;
        this.vm = vm;

        /*在这里将观察者本身赋值给全局的target,只有被target标记过的才会进行依赖收集*/
        Dep.target = this;
        /*Github:https://github.com/answershuto*/
        /*触发渲染操作进行依赖收集*/
        this.cb.call(this.vm);
    }

    update () {
        this.cb.call(this.vm);
    }
}
ログイン後にコピー

Start dependency collection

class Vue {
    constructor(options) {
        this._data = options.data;
        observer(this._data, options.render);
        let watcher = new Watcher(this, );
    }
}

function defineReactive (obj, key, val, cb) {
    /*在闭包内存储一个Dep对象*/
    const dep = new Dep();

    Object.defineProperty(obj, key, {
        enumerable: true,
        configurable: true,
        get: ()=>{
            if (Dep.target) {
                /*Watcher对象存在全局的Dep.target中*/
                dep.addSub(Dep.target);
            }
        },
        set:newVal=> {
            /*只有之前addSub中的函数才会触发*/
            dep.notify();
        }
    })
}

Dep.target = null;
ログイン後にコピー

オブザーバー Watcher インスタンスをグローバル Dep.target に割り当て、レンダリング操作をトリガーします。Dep.target でマークされた依存関係のみが収集されます。 Dep.target を持つオブジェクトは Watcher インスタンスを subs にプッシュします。オブジェクトが変更されて setter 操作がトリガーされると、dep はレンダリングのために subs 内の Watcher インスタンスの update メソッドを呼び出します。

この記事はここで終了しています。さらに興味深いコンテンツについては、PHP 中国語 Web サイトの JavaScript ビデオ チュートリアル 列に注目してください。

以上がvue の応答性の原則と依存関係の収集の概要 (コード付き)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:segmentfault.com
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート