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

推薦する

Linux 環境変数とプロセス アドレス空間の概要

目次Linux 環境変数とプロセスアドレス空間コードを通じて環境変数を取得するプロセスアドレス空間な...

React コンポーネント通信ルーティングパラメータ転送 (react-router-dom)

目次最近Reactを勉強していて、今は仕事でVueを使っています。学習の過程で、両者を比較して理解を...

優れたユーザー エクスペリエンス デザイナーが行うべき 5 つのこと (画像とテキスト)

この記事は、@C7210 によって翻訳されたブログ「Usability Counts」からの翻訳です...

IE 環境での css-vars-ponyfill の使用に関する詳細な説明 (nextjs ビルド)

css-vars-ポニーフィルCSS 変数を使用して Web ページのスキニングを実現すると、互換...

Linux システムでの virtuoso データベースの詳細なインストールと使用

最近、リンク データについていくつか調査していて、rdf データベースを使用する必要があったため、v...

MySQL の異常なエラー ERROR: 2002 を解決する方法

最近、MySQL の起動中にエラーが発生しました。エラー メッセージは次のとおりです。 エラー 20...

Docker5フル機能の港湾倉庫構築プロセス

Harbor は、Docker イメージを保存および配布するためのエンタープライズ レベルのレジスト...

MySQL ストレージエンジンの簡単な紹介

1. MySQL アーキテクチャストレージ エンジンを紹介する前に、まずは MySQL アーキテクチ...

バックエンドから返される 100,000 個のデータをフロントエンドでより適切に表示するにはどうすればよいですか?

目次予備作業バックエンド構築フロントエンドページダイレクトレンダリングsetTimeout ページン...

HTML テーブル マークアップ チュートリアル (10): セル パディング属性 CELLPADDING

セルのパディングは、セルの内容と境界線の間の距離です。基本的な構文<TABLE セルパディング...

MySQL 8.0 の新機能の分析 - トランザクション データ ディクショナリとアトミック DDL

序文トランザクション データ ディクショナリとアトミック DDL は、MySQL 8.0 で導入され...

無視されたDOCTYPE記述の分析

doctype もその 1 つです。 <!DOCTYPE HTML PUBLIC "...

QT が MYSQL データベースに接続するための詳細な手順

最初のステップは、対応するデータベースモジュール(sql)をプロジェクトファイル( .pro )に追...

CentOS 環境で NFS リモート ディレクトリ マウントを使用する手順の紹介

目次1. NFS の概要2. NFS構築1. NFSサーバーの構築2. NFSクライアントの構築3....

nginx のロードバランシングとリバースプロキシの説明

目次負荷分散負荷分散分類1. DNS 負荷分散2. IP負荷分散3. リンク層の負荷分散4. ハイブ...