Vueは双方向データバインディングを実装します

Vueは双方向データバインディングを実装します

この記事の例では、双方向データバインディングを実装するためのVueの具体的なコードを参考までに共有しています。具体的な内容は次のとおりです。

Vueの配列とオブジェクトは異なるバインディングメソッドを使用します

1. Vueオブジェクトデータバインディング

(1)データ検出

jsでは、Object.defineProperty()とES6プロキシを使用してオブジェクトを検出します。

vue2.x では、Object.defineProperty() を使用してオブジェクト上のデータを検出します。まず、次のコードを使用して Object.defineProperty をカプセル化します。

関数defineReactive(データ、キー、値){
    if(typeof val === 'object') 新しいオブザーバー(val)
    dep = new Dep();
    Object.defineProperty(データ、キー、値) {
    列挙可能: true、
    設定可能: true、
    取得: 関数 () {
        依存関係
        戻り値:
    },
    設定: 関数() {
        if(val === newVal) {
            戻る ;
        }
        val = 新しいVal;
        dep.notify()
    }
}
}

渡す必要があるパラメータは、データ、キー、および val のみです。データ内のキーからデータが読み取られるたびに Get がトリガーされ、データが変更されるたびに set がトリガーされます。

(2)依存関係の収集

最初に依存関係を収集し、プロパティが変更されたときに、収集した依存関係をループで再度トリガーします。ゲッターで依存関係を収集し、セッターで依存関係をトリガーします。

依存クラス Dep

デフォルトクラス Dep をエクスポートします {
    コンストラクタ() {
        this.subs = []
    }
    
    サブルーチンを追加します。
        this.subs.push(サブ)
    }
    
    サブルーチンを削除します
        削除(this.subs, sub)
    }
    
    依存する() {
        if(ウィンドウ.ターゲット) {
            this.addSub(ウィンドウ.ターゲット)
        }
    }
    
    通知() {
        const subs = this.subs.slice()
        for(let i = 0, l = subs.length; i < l; i++) {
            subs[i].update()
        }
    }
}
 
関数remove(arr, item) {
    (arr.length)の場合{
        定数インデックス = arr.indexOf(item)
        if(インデックス > -1) {
            arr.splice(インデックス, 1) を返す
        }
}
}

ウォッチャークラスは、私たちが収集した依存関係です

デフォルトクラスWatcherをエクスポートします{
    コンストラクタ(vm, expOrFn, cb) {
        this.vm = vm
        this.getter = parsePath(expOrFn)
        this.cb = cb
        this.value = this.get()
    }
    
    得る() {
        window.target = これ
        値を this.getter.call(this.vm, this.vm) にします。
        window.target = 未定義
        戻り値
    }
    
    アップデート() {
        const oldValue = this.value
        this.value = this.get()
        this.cb.call(this.vm、this.value、oldValue) の呼び出し
    }
}

(3)全てのキーを再帰的に検出する(オブザーバー)

エクスポートクラスObserver {
    コンストラクタ(値) {
        this.value = 値;
        
        if(!Array.isArray(値)) {
            this.walk(値)
        }
    }
    歩く(オブジェクト) {
        定数キー = Object.keys(obj)
        for(let i = 0; i < keys.length; i++) {
            定義Reactive(obj, キー[i], obj[キー[i]])
        }
    }
}

Observerクラスはオブジェクトのすべてのプロパティをレスポンシブにします

2.配列変更検出

(1)配列の変更を追跡するには、インターセプターを使用してプロトタイプメソッドをオーバーライドします。

const arrayProto = Array.prototype
エクスポート const arrayMethods = Object.create(arrayProto);
// 配列プロトタイプと同じオブジェクトをインターセプターとして ['push','pop','shift','unshift','splice','sort','reverse'].forEach(function (method) {
    const オリジナル = arrayProto[メソッド]
    Object.defineProperty(配列Methods, メソッド, {
        値: 関数ミューテーター(...args) {
              元の値を返す。(this, args)
        },
        列挙可能: false、
        書き込み可能: true、
        設定可能: true
    })
})

インターセプターオーバーライドプロトタイプには1つの文しかありません

value.__proto__ = 配列メソッド

__proto__プロパティがない場合、VueはこれらのarrayMethodsを検出された配列にマウントします。

配列は、ゲッターで依存関係を収集するのに対し、配列によってトリガーされる依存関係はインターセプターにあるという点でオブジェクトに似ています。

配列の依存関係は Observer インスタンスに保存され、ゲッターとインターセプターの両方からアクセスできる必要があります。

__ob__ は列挙不可能な属性であり、この属性の値は現在の Observer インスタンスです。

Dep インスタンスを Observer 属性に保存します。値にすでに __ob__ 属性がある場合は、値の変更が繰り返し検出されるのを避けるために、Observer インスタンスを再度作成する必要はありません。

配列の依存関係などの通知を送信する

this.__ob__.dep.notify();

(2)データの変化を検知するための具体的な方法

配列内の各項目をループし、observe関数を実行して変更を検出します。

配列を観察(アイテム) {
    for(let i = 0; l = items.length; i < l; i++) {
        アイテム[i]を観察します。    
    }
}

配列は新しい要素を検出する必要がある

push、unshift、spliceなどのメソッドをインターセプトし、挿入された引数を格納することで

if(挿入) ob.observeArray(挿入)

要約:

配列は Object とは異なる方法で変更を追跡するため、変更を追跡するために配列のプロトタイプを上書きするインターセプターを作成します。グローバル Array.prototype を汚染しないように、Observer では __proto__ のみを使用して、変更を検出する必要がある配列のプロトタイプを上書きします。

Array は Object と同じ方法で依存関係を収集します。Object はゲッターで収集され、インターセプターでトリガーされ、依存関係は Observer インスタンスに保存されます。 Observer では、検出された各データを __ob__ でマークし、this(Observer) を __ob__ に保存します。これは主に、同じデータが 1 回だけ検出されることを保証するためです。さらに、__ob__ を通じて Observer インスタンスに保存された依存関係を簡単に取得できます。配列の各項目を応答可能にするには、配列をループする必要があります。配列に新しい要素が追加されると、パラメータを抽出し、observeArray を使用して新しいデータの変更を検出します。配列の場合、プロトタイプ メソッドのみをインターセプトでき、一部の固有のメソッドはインターセプトできません。

以上がこの記事の全内容です。皆様の勉強のお役に立てれば幸いです。また、123WORDPRESS.COM を応援していただければ幸いです。

以下もご興味があるかもしれません:
  • Vue mvvm データレスポンス実装
  • vue の mvvm モードの説明
  • Vue.js テンプレート構文の詳細な説明
  • Vueデータバインディングの原則の分析
  • Vue の基本 MVVM、テンプレート構文、データバインディング

<<:  JDBC および MySQL 一時テーブルスペースの詳細な分析

>>:  Linux でファイルをあいまい検索するのに適したコマンドは何ですか?

推薦する

JS クロスドメイン ソリューション React 構成 リバース プロキシ

クロスドメインソリューションjsonp (get をシミュレート) CORS (クロスオリジンリソー...

MySQL チュートリアル: サブクエリの例の詳細な説明

目次1. サブクエリとは何ですか? 2. サブクエリはどこに表示されますか? 3. Whereサブク...

印刷広告を成功させるための「3I」基準

国内の多くの広告主にとって、印刷広告の制作と評価は、しばしばかなり主観的です。自分の感情や美的感覚に...

Mac で docker と kubectl の自動補完コマンドを追加する方法

kubectl の紹介kubectl は、k8s クラスターを操作するためのコマンドライン ツールで...

ウェブページ作成に役立つコード

<br />ホームページの右側にあるスクロールバーを削除するにはどうすればよいですか? ...

Office ファイルのオンライン プレビュー用の Vue サンプル コード

最近、電子アーカイブに取り組んでおり、バックエンドではファイルの Huawei Cloud OSS ...

Docker デプロイメント Consul 構成プロセスの分析

コマンドを実行docker run -d --name consul -p 8500:8500 co...

dockerでマウントされたディレクトリが読み書きできない問題を解決する

次のコマンドを使用してコンテナを作成し、ローカルの /home/dock/Downloads ディレ...

MySQL の制限ページング最適化ソリューションの実装に関する簡単な説明

MySQL のページングステートメントの使用制限Oracle や MS SqlServer と比較す...

Vue-CLI マルチページディレクトリパッケージ化手順の記録

ページディレクトリ構造 デフォルトの HTML テンプレート ファイル public/index.h...

JavaScriptプロトタイプチェーン図のまとめと実践

目次プロトタイプチェーンプロトタイプチェーンに基づいてシンプルなJQueryライブラリを実装すること...

vite2.0 設定学習の詳しい説明(typescript 版)

導入悠宇希の原文です。 vite は Vue CLI に似ています。vite も、基本的なプロジェク...

CSSは、閉じることができるマスクレイヤーを備えたポップアップウィンドウ効果を実装します。

実際の開発ではポップアップウィンドウがよく使われます。CSS3を勉強していたときに、閉じることができ...