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 イメージ サーバーを構築する方法

推薦する

Alibaba Cloud Server への Web プロジェクトのデプロイについて (5 つの手順)

1.まずAlibaba Cloudのウェブサイトにログインしてアカウントを登録し、サーバータイプを...

Nginx サーバーの https 設定方法の例

Linux: Linux バージョン 3.10.0-123.9.3.el7.x86_64 ngin...

コンポーネントベースのフロントエンド開発プロセスの詳細な説明

背景<br />フロントエンドを担当する学生は、ページが多すぎると煩雑になるため、開発プ...

Vueはシンプルなマーキー効果を実装します

この記事では、Vueの具体的なコードを共有して、シンプルなマーキー効果を実現しています。具体的な内容...

CentOS で LibreOffice を使用してドキュメント形式を変換する方法

プロジェクト要件では、アップロードされたドキュメントの前処理が必要です。ユーザーが doc 形式でド...

Alibaba Cloud centos7にmysql8.0.22をインストールする詳細なチュートリアル

1. MySQLインストールパッケージをダウンロードするまず、https://dev.mysql.c...

Vue 構成リクエストの複数サーバーソリューションの詳細な説明

1. 解決策1.1 インターフェースコンテキストパスの説明2 つのバックエンド インターフェイス サ...

Bootstrap 3.0 学習ノートのボタンとドロップダウン メニュー

前回の記事はBootstrap CSS部分の簡単なレビューであり、多くの詳細が見落とされていました。...

MySQLの明示的な型変換の簡単な分析

CAST関数前回の記事では、型変換を表示するために使用する CAST 関数について説明しました。暗黙...

MySQL の冗長インデックスと重複インデックスの詳細な説明

MySQL では、同じ列に複数のインデックスを作成できます。意図的であるかどうかにかかわらず、MyS...

HTML タグ マーキーはさまざまなスクロール効果を実現します (JS 制御なし)

ページの自動スクロール効果は JavaScript で実現できますが、今日偶然、JS 制御なしでさま...

MySQL 圧縮版 zip のインストールに関する問題の解決策

本日、MySQLの圧縮版をインストールする際に問題が発生しました。サービスが起動できず、2、3時間苦...

JavaScript で 24 以上の配列メソッドを手動で実装する

目次1. トラバーサルクラス1. 各2. 地図3. すべての4. いくつか5. フィルター6. 減ら...

エンコードが utf-8 に設定されている場合に Web ページが文字化けする問題の解決策

最近、PHP で Web ページを書いているときに、エンコードを UTF-8 に設定しました。しかし...

MySQL 8.0.24 リリースノートのいくつかの改善点

目次1. 接続管理2. オプティマイザレベルでの改善3. 機能の改善4. パフォーマンススキーマの最...