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

推薦する

VMware Workstation Pro は Win10 ピュア バージョンのオペレーティング システムをインストールします

この記事では、VMware Workstation Pro で Win10 オペレーティング システ...

Tomcat の maxPostSize 設定に関する問題と注意事項

1. maxPostSize を設定する理由は何ですか? tomcat コンテナには送信データのサイ...

jquery+springbootでファイルアップロード機能を実現

この記事の例では、ファイルアップロード機能を実現するためのjquery+springbootの具体的...

Linuxでホスト名を永続的に変更する方法

ホスト名を変更する場合は、以下の手順に従ってください。ホスト名の使用hostnameコマンドを使用す...

Docker構成 Alibaba Cloud Container Serviceの操作

Alibaba Cloud Dockerコンテナサービスの設定Alibaba Cloud Image...

DockerコンテナはホストのMySQL操作にアクセスする

背景:インターフェイスを提供する Flask プロジェクトがあり、これは Docker コンテナを使...

JSに関する7つの面接の質問、あなたはいくつ正しく答えられますか

序文JavaScript では、これは関数呼び出しコンテキストです。この動作が非常に複雑であるからこ...

EDMをHTMLで記述する際の注意点まとめ(メール送信時の一般的な注意点)

フォーマットエンコーディング1. ページの幅は600~800px、長さは1024px以内に設定してく...

Dockerコンテナを介してランプアーキテクチャを構築するプロセス

目次1. Centosイメージを取得する2. nginxイメージをビルドする3. MySQLイメージ...

WeChatアプレットでQRコードを識別するために長押しする実装プロセス

序文公式アカウントのQRコードは長押しで認識できることは皆さんご存じですが、ミニプログラムに対する制...

jsはキャンバスに基づいて時計コンポーネントを実装します

圧縮アップロード画像、スクラッチカード、ポスター作成、チャートプラグインなど、フロントエンド開発にお...

MySQL の分離レベルの包括的な分析

データベースが同じデータ バッチを同時に追加、削除、および変更すると、ダーティ書き込み、ダーティ読み...

MySQLは、統計クエリを最適化するために、sum、case、whenを巧みに使用します。

私は最近、会社で統計レポートの開発に関わるプロジェクトに取り組んでいました。データの量が比較的多かっ...

JavaScript 配列重複排除問題の詳細な研究

目次序文 👀リサーチを始めましょう🐱‍🏍オリジナル🧶 indexOf を使用した元の方法の最適化 ✍...