Vue2.x の応答性の簡単な説明と例

Vue2.x の応答性の簡単な説明と例

1. Vue レスポンシブの使用法を確認する

​ Vue の応答性は、私たち全員がよく知っています。 Vue のデータ オブジェクト内のプロパティを変更すると、ページ内でプロパティが参照される場所もそれに応じて変更されます。これにより、DOM を操作してデータ バインディングを実行する必要がなくなります。

2. Vue レスポンシブ実装の分析

Vue のレスポンシブ原則については、公式 Web サイトにテキストによる説明があります (https://cn.vuejs.org/v2/guide/reactivity.html)。

Vueは主にデータハイジャックとオブザーバーモードを通じて実装されています

データハイジャック:

vue2.x は内部的に Object.defineProperty を使用します https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty

vue3.x が内部で使用するプロキシ https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Proxy

オブザーバーパターン: https://www.jb51.net/article/219790.htm

内部メンバー図

各メンバーの機能

ビュー:

データのメンバーをVueインスタンスに注入し、データのメンバーをゲッターとセッターに変換します。

オブザーバー:

データオブジェクト内の単純型データとオブジェクトを監視し、データが変更されたときにDepに通知します。

コンパイラ:

各要素の命令/差分式を解析し、対応するデータに置き換えます

出発地:

オブザーバーモードでの通知機能、オブザーバーの追加、データの変更時にオブザーバーに通知する

ウォッチャー:

データ内のプロパティを参照する各場所には、ビューの更新を担当するウォッチャーオブジェクトがあります。

付録: データオブジェクト内のプロパティは観測対象として機能し、データオブジェクト内のプロパティが参照される場所は観測者として機能します。

3. Vue レスポンシブ ソースコード実装

Vueオブジェクトの実装

関数

  • 初期化パラメータの受け入れを担当
  • データ内の属性をデータインスタンスに注入し、ゲッターとセッターに変換する
  • データ内のすべての属性の変更を監視するためにObserverを呼び出す
  • コンパイラを呼び出して、命令と差分式を解析します。
クラス Vue{
    コンストラクタ(オプション){
        // 1. 渡された属性を属性を通じて保存します。this.$options= options||{};
        this.$data = オプション.data||{};
        this.$el = typeof options.el ==='string' ? document.querySelector(options.el) : options.el;
        // 2. データパラメータのデータをゲッターとセッターに変換し、Vue インスタンスにマウントします。this._proxyData(this.$data)
        // 3. データの変更を監視するために observe オブジェクトを呼び出します new Observer(this.$data)
        // 4. コンパイラオブジェクトを呼び出してページをレンダリングする new Compiler(this)
    }
    _proxyData(データ){
        if (data&&Object.keys(data).length>0){
             for (const キー in データ) {
                Object.defineProperty(this,key,{
                    設定可能:true、
                    列挙可能:true、
                    得る(){
                        データを返す[キー]
                    },
                    設定(値){
                        if (データ[キー]===値) {
                            戻る;
                        }
                        データ[キー]=値;
                    }
                })
             }
        }
    }
}

オブザーバーオブジェクトの実装

関数

  • データオプションの属性をハイジャックする
  • データ内の属性もオブジェクトである場合は、それを再帰的にレスポンシブオブジェクトに変換します。
  • データが変更されたときに通知を送信する
//データハイジャッククラスObserver {
    コンストラクタ(データ) {
        this.walk(データ)
    }
    ウォーク(データ) { 
        //1. データがオブジェクトかどうかを判定する if (!data || typeof data !== 'object') {     
            戻る
        }
        //2. ループ呼び出しdefineReactiveでdataObject.keys(data).forEach(key => {をハイジャックする
            this.defineReactive(データ、キー、データ[キー])
        })
    }
    定義Reactive(オブジェクト、キー、値) {
        //通知機能を作成する const dep = new Dep()
        //参照オブジェクトのプロパティをレスポンシブにするには、walk を使用します。this.walk(val)
        const は、次のようになります。
        Object.defineProperty(obj, キー, {
            設定可能: true、
            列挙可能: true、
            得る() {
                //Notifier はオブザーバーを収集します Dep.target && dep.addSub(Dep.target)
                戻り値:
            },
            set(newVal) {
                (newVal === val)の場合{
                    戻る;
                }
                val = 新しいVal;
                that.walk(新しい値)
                // 監視対象オブジェクトが変更されると、通知オブジェクトは各オブザーバーに通知を送信します dep.notify()
            }
        })
    }
}

オブジェクト実装をコンパイルする

関数

  • テンプレートのコンパイル、命令の解析、微分表現を担当
  • ページの最初のレンダリングを担当
  • データが変更されたときにビューを再レンダリングする責任がある
//コンパイラクラス Compiler {
    コンストラクタ(vm) {
        this.el = vm.$el;
        this.vm = vm;
        this.compile(this.el)
    }
    //テンプレートをコンパイルして、ノードがテキストノードか要素ノードかを判断する compile(el) {
        childNodes を el.childNodes とします。
        //子ノードの最初の層を処理する Array.from(childNodes).forEach(node ​​=> {
            if (this.isTextNode(ノード)) {
                this.compileText(ノード)
            } それ以外の場合は (this.isElementNode(node)) {
                this.compileElement(ノード)
            }
            //現在のノードに子ノードがある場合は、コンパイル命令を再帰的に呼び出します。if (node.childNodes && node.childNodes.length) {
                this.compile(ノード)
            }
        })
    }

    //要素ノードをコンパイルし、命令を処理する compileElement(node) {  
        //すべての命令を走査する Array.from(node.attributes).forEach(attr => {
            //ディレクティブノードかどうかを判断します if (this.isDirective(attr.name)) {
                定数 nodeName = attr.name;
                定数キー = attr.nodeValue;
                const ディレクティブ = nodeName.substr(2)
                this.updater(ディレクティブ、ノード、キー)
            }
        }) 
    }
    アップデータ(ディレクティブ、ノード、キー){
        const updaterFn = this[ディレクティブ+"Updater"]
        updaterFn && updaterFn.call(this,node,this.vm[key],key)
    }
    //vテキスト
    textUpdater(ノード、値、キー){
        node.textContent=値
        //v-text式が使用される場所はオブザーバーです new Watcher(this.vm,key,newValue => {
            node.textContent = 新しい値
        })
    }
    //vモデル
    modelUpdater(ノード、値、キー){
        ノード.値 =値
        //v-model式が使用される場所はオブザーバーです new Watcher(this.vm,key,newValue => {
            node.value = 新しい値
        })
      //双方向バインディングを実現するnode.addEventListener('input',()=>{
            this.vm[キー] = ノード.値
        })
    }
    //v-html
    htmlUpdater(ノード、値、キー){
        node.innerHTML = 値
        //v-html式が使用される場所はオブザーバーです new Watcher(this.vm,key,newValue => {
            node.innerHTML = 新しい値
        })
    }

    //差分式の処理 compileText(node) {
        //正規表現の一致の違い let reg = /\{\{(.+?)\}\}/
        //正規表現を使用してノードのテキストコンテンツと一致させ、一致する場合は置き換えます if (reg.test(node.textContent)) {
            //補間式のキーを取得する
            キーを RegExp.$1 とします。
            値を node.textContent とします。
            node.textContent = value.replace(reg, this.vm[key])

            //差分式が使用される場所はオブザーバーです new Watcher(this.vm,key,newValue => {
                node.textContent = 新しい値
            })
        }
    }

    //ディレクティブかどうか isDirective(attrName) {
        attrName.startsWith('v-') を返します。
    }

    //テキストノードかどうか isTextNode(node) {
        node.nodeType === 3 を返します
    }

    //要素かどうか isElementNode(node) {
        node.nodeType === 1 を返します
    }
}

依存関係オブジェクトの実装

関数

  • 依存関係を収集し、オブザーバーを追加する
  • すべての観察者に通知する
//通知クラスclass Dep {
    コンストラクタ() {
        //ストレージオブザーバー this.subs = []
    }

    /**
     * オブザーバーを集める */
    サブルーチンを追加します。
        if (sub && sub.update) {
            this.subs.push(サブ)
        }
    }

    /**
     * 状態の変化をオブザーバーに通知する */
    通知() {
        this.subs.forEach(sub => {
            サブ.更新()
        })
    }
}

ウォッチャーオブジェクトの実装

関数

  • データが変更されると、DepはすべてのWatcherインスタンスにビューを更新するように通知します。
  • 自身をインスタンス化するときに、自身をDepオブジェクトに追加する
//オブザーバークラスクラス Watcher {
    コンストラクタ (vm,key,cb) {
        //Vue インスタンス this.vm =vm;
        //データ内のキーオブジェクト this.key =key;
        // ビューを更新するためのコールバック関数 this.cb = cb
        //現在のオブザーバーインスタンスをDepのターゲット静的プロパティに保存します。Dep.target = this
        //Observe の getter メソッドをトリガーし、現在のインスタンスを Dep.subs に保存します //データ内のキーに対応する古い値 this.oldValue = this.vm[this.key]
        依存関係ターゲット = null
    }
    //各オブザーバーには状態を変更するための更新メソッドがあります update(){
        const newValue = this.vm[this.key]
        if ( this.newValue === this.oldValue ) {
            戻る
        }
        this.cb(新しい値)
    }
}

テスト

<ヘッド>
    <メタ文字セット="UTF-8">
    <meta http-equiv="X-UA-compatible" content="IE=edge">
    <meta name="viewport" content="width=デバイス幅、初期スケール=1.0">
    <title>インデックス</title>
    <script src="./js/dep.js"></script>
    <script src="./js/watcher.js"></script>
    <script src="./js/compiler.js"></script>
    <script src="./js/observer.js"></script>
    <script src="./js/vue.js"></script>
</head>
<本文>
    <p id="アプリ">
        <h1>差分式</h1>
        <h3>{{メッセージ}}</h3>
        <h3>{{カウント}}</h3>
        <h1>v-テキスト</h1>
        <p v-text='メッセージ'></p>
        <h1>vモデル</h1>
        <input type="text" v-model="msg" attr="msg">
        <input type="text" v-model="count">
        <h1>v-html</h1>
        <p v-html="htmlテキスト"></p>
    </p>
    <スクリプト>
        vm = new Vue({
            el:"#アプリ",
            データ:{
                メッセージ: '情報',
                count:'数量', 
		人:{name:'张三'},
                htmlText:"<p style='color:red'>こんにちは</p>"
            }
        })
    </スクリプト>
</本文>

これで、Vue2.x のレスポンシブ性の簡単な説明と例についての記事は終了です。Vue2.x のレスポンシブ性に関するより関連性の高いコンテンツについては、123WORDPRESS.COM の過去の記事を検索するか、以下の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。

以下もご興味があるかもしれません:
  • Vue2 レスポンシブシステム非同期キュー
  • Vue2 レスポンシブ システムの紹介
  • Vue2 レスポンシブシステム ブランチ切り替え
  • Vue2 レスポンシブシステムのネスト
  • Vue2 レスポンシブシステム: ディープレスポンス
  • Vue2 レスポンシブ システム アレイ
  • Vue2 レスポンシブ システムの設定と削除
  • vue2 の応答性の欠点

<<:  MySQLデータベースはMMM高可用性クラスタアーキテクチャを実装します

>>:  Docker で Nginx イメージ サーバーを構築する方法

推薦する

CentOS 7.0 (mysql-5.7.21) で複数の MySQL インスタンスを起動する方法

設定手順Linux システム: CentOS-7.0 MySQL バージョン: 5.7.21 Lin...

div の幅が width:100% に設定されていて、パディングまたはマージンが親要素を超えてしまう問題の解決方法

序文この記事では、div の幅を 100% に設定し、親要素を超えてパディングまたはマージンを設定す...

JS関数の継承について学ぶ記事

目次1. はじめに: 2. プロトタイプチェーン継承: 3. コンストラクタ継承の借用(オブジェクト...

MySQL サービスとデータベース管理

目次1. サービスの開始と停止の手順1.1 Windows での MySQL 5.7 の公式 MSI...

Ubuntu の空き容量を増やす 5 つの簡単な方法

序文ほとんどの人は、システム ディスク ストレージが少ないときにこの操作を実行するか、Linux シ...

JDBC を使用して Mysql データベースに接続する際に発生する可能性のある問題の概要

まず、いくつかの概念を明確にします。 JDBC: Javaデータベース接続、Oricalによって規定...

Linux ディスクのマウント、パーティション分割、容量拡張操作を実装する方法

基本概念操作の前に、まずいくつかの基本的な概念を理解する必要がありますディスクLinux システムで...

Sitemesh チュートリアル - ページ装飾技術の原理と応用

1. 基本概念1. Sitemeshはページ装飾技術です。 1 : フィルターを通してページアクセス...

Node+Express テストサーバーのパフォーマンス

目次1 テスト環境1.1 サーバーハードウェア1.1.1 t2.マイクロ1.1.2 c5.large...

MySQL でストアド プロシージャを作成し、データ テーブルに新しいフィールドを追加する方法の分析

この記事では、例を使用して、MySQL でストアド プロシージャを作成し、データ テーブルに新しいフ...

Docker で nginx の https を設定する方法

https をサポートしていない Web サイトは、ブラウザによって徐々に安全でないとマークされるた...

mysql の not equal to null と equal to null の書き方の詳細説明

1. テーブル構造 2. 表データ 3. クエリのteacher_nameフィールドは空にすることは...

Centos7.3は起動時に自動的に起動または指定されたコマンドを実行します

Centos7では、/etc/rc.d/rc.localファイルの権限が削減されており、実行権限があ...

html2canvasで画像が正常にキャプチャできない時の解決方法

質問まず、私が遭遇した問題についてお話しします。まず、そういった需要があるわけです。フロントエンドは...

コマンドを使用してMySQLデータベース(de1)を作成する方法

1. MYSQLに接続するフォーマット: mysql -h ホストアドレス -u ユーザー名 -p ...