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 でファイルをあいまい検索するのに適したコマンドは何ですか?

推薦する

nginx で http でアクセスする Web サイトを https に変更する方法

目次1. 背景2. 前提条件https:証明書システム: 3. 操作プロセス3.1 証明書の生成3....

「さらに表示」ボタンによる複数行テキストの切り捨てに関する考察

最近、たまたまこの小さな要件に遭遇しました。昔、JS を使用してこれを処理したことを覚えていますが、...

Docker+K8S+GitLab/SVN+Jenkins+Harbor をベースにした継続的インテグレーション配信環境の構築に関する詳細なチュートリアル

目次環境設定の概要1.K8Sとは何ですか? 2. K8S を使用する理由3. K8S を使用する利点...

MySQLの基本的な共通コマンドの概要

目次MySQL の基本的な共通コマンド1. SQL文2. テーブルを作成する3. フィールドのプロパ...

nginx でネストされた if メソッドを実装する方法

Nginx はネストされた if ステートメントをサポートしておらず、if ステートメントでの論理判...

MySQL および Oracle のバッチ挿入 SQL の一般的な記述例

目次例えば:一般的な執筆:要約する例えば:次に、データベースのUSERテーブルにUserオブジェクト...

MySQL 8.0.12 解凍版インストールチュートリアル個人テスト!

Mysql8.0.12 解凍版のインストール方法をテストしましたので、ご参考までに1. ダウンロー...

Nacos で MySQL8 を設定する方法

1. MySQLデータベースnacos_configを作成する2. データベース nacos_con...

Web デザインのための 5 つのシンプルな XHTML Web フォーム

Web デザイン 5 におけるシンプルな XHTML Web フォーム。 テクニック 1: ラベル ...

Alibaba Cloud ECS サーバーでポート 8080 を開く方法

セキュリティ上の理由から、Alibaba Cloud Server ECS にはデフォルトで独自のセ...

Vue lazyload 画像遅延読み込み例の詳細な説明

ドキュメント: https://github.com/hilongjw/vue-lazyload 1...

虫眼鏡ケースのJavaScriptオブジェクト指向実装

この記事では、参考までに、虫眼鏡のJavaScriptオブジェクト指向実装の具体的なコードを紹介しま...

HTMLフォーム送信方法のケーススタディ

フォームの送信方法をまとめると次のようになります。 1. 送信ボタンを使用して送信します。送信ボタン...

Linux システムに Zookeeper サービスをインストールする方法

1. /usr/local/services/zookeeper フォルダを作成します。 mkdir...

無効な Nginx クロスドメイン設定 Access-Control-Allow-Origin の解決策

nginx バージョン 1.11.3次の構成を使用すると、検証は無効になり、クロスドメインの問題が依...