Vue の DOM の非同期更新の簡単な分析

Vue の DOM の非同期更新の簡単な分析

データ オブジェクト: vue の data メソッドによって返されるオブジェクト。

Dep オブジェクト: 各データ属性は、このデータを使用するすべての Watcher オブジェクトを収集するための Dep を作成します。

ウォッチャーオブジェクト: 主にDOMのレンダリングに使用されます

Vue が DOM を非同期更新する原理

Vue でのデータ更新は非同期であるため、データを変更した後、変更された DOM 要素をすぐに取得することはできません。

1 実際の DOM 要素を取得できるのはいつですか?

Vue の nextTick コールバック内。

2 Vue は最新の DOM を取得するために nextTick メソッドを使用する必要があるのはなぜですか?

2.1 vue が Watcher を呼び出してビューを更新する場合、直接更新するのではなく、更新する必要がある Watcher を Queue キューに追加し、特定の更新メソッド flushSchedulerQueue を nexTick に渡して呼び出します。

// src > core > observer > watcher.js + scheduler.js // データが更新されると、次のコードが順番に実行されます // 1. Data.set をトリガーします
// 2. dep.notifyを呼び出す
// 3. Dep は関連するすべての Watcher を走査し、更新メソッドを実行します。class Watcher {
  // 4. 更新操作を実行する update() {
    キューウォッチャー(これ);
  }
}

定数キュー = [];

関数queueWatcher(ウォッチャー: ウォッチャー) {
  // 5. 現在の Watcher を非同期キューに追加します。queue.push(watcher);
  // 6. 非同期キューを実行し、コールバック nextTick(flushSchedulerQueue); を渡します。
}

// ビューを更新するための特定のメソッド function flushSchedulerQueue() {
  ウォッチャー、ID;
  // ソートし、最初に親ノードをレンダリングしてから、子ノードをレンダリングします。 // これにより、次のような不要な子ノードのレンダリングを回避できます。親ノードで v-if が false である子ノードはレンダリングする必要がありません。 queue.sort((a, b) => a.id - b.id);
  // バッチ更新のためにすべてのウォッチャーを走査します。
  (インデックス = 0; インデックス < キューの長さ; インデックス++) {
    ウォッチャー = キュー[インデックス];
    // DOMを更新する
    ウォッチャーを実行します。
  }
} 

2.2 nextTick -- 渡された flushSchedulerQueue をコールバック配列に追加し、timerFunc メソッドを実行します。

const コールバック = [];
timerFunc を作成します。

関数 nextTick(cb?: 関数、ctx?: オブジェクト) {
  _resolve を実行します。
  // 1. 渡されたflushSchedulerQueueメソッドをコールバック配列に追加します callbacks.push(() => {
    cb.call(ctx);
  });
  // 2. 非同期タスクを実行する // このメソッドは、ブラウザの互換性に応じて異なる非同期戦略 timerFunc() を選択します。
}

2.3 timerFunc メソッド - ブラウザの互換性に基づいて作成された非同期メソッドです。このメソッドを実行すると、flushSchedulerQueue メソッドが呼び出され、特定の DOM 更新が実行されます。

timerFunc を作成します。
// Promiseと互換性があるかどうかを判定する
if (typeof Promise !== "undefined") {
  タイマー関数 = () => {
    Promise.resolve() を実行してから (コールバックをフラッシュします);
  };
  // MutationObserverと互換性があるかどうかを判定する
  // https://developer.mozilla.org/zh-CN/docs/Web/API/MutationObserver
} そうでない場合 (typeof MutationObserver !== "undefined") {
  カウンターを1にします。
  const オブザーバー = 新しい MutationObserver(flushCallbacks);
  定数textNode = document.createTextNode(String(counter));
  オブザーバー.observe(textNode, {
    文字データ: true、
  });
  タイマー関数 = () => {
    カウンター = (カウンター + 1) % 2;
    textNode.data = String(カウンター);
  };
  // setImmediateと互換性があるかどうかを判定する
  // このメソッドは一部の IE ブラウザに存在します} else if (typeof setImmediate !== "undefined") {
  // これはマクロタスクですが、setTimeout よりも優れています timerFunc = () => {
    即時設定(コールバックをフラッシュ)。
  };
} それ以外 {
  // 上記の方法がわからない場合は、setTimeout 0 を使用します
  タイマー関数 = () => {
    タイムアウトを設定します(コールバックをフラッシュします、0);
  };
}

// 非同期実行後、すべてのコールバックメソッドを実行します。つまり、flushSchedulerQueueを実行します。
関数flushCallbacks() {
  (i = 0 とします; i < コピー数.長さ; i++) {
    コールバック[i]();
  }
} 

2.4 論理的判断力を向上させる

2.4.1 同じウォッチャーをキューに追加しないように、has フラグを決定します。

2.4.2 待機フラグを決定し、1ティック以内にすべてのウォッチャーを更新します。

2.4.3 フラッシュ フラグを決定し、Watcher がレンダリングされるときに生成される可能性のある新しい Watcher を処理します。

v-if 条件がトリガーされると、新しく追加された Watcher がレンダリングされます。

ヒント: nextTick は、Promise、setTimeout、その他のメソッドによってシミュレートされる単なる非同期タスクです。

3 なぜ this.$nextTick は更新された DOM を取得できるのでしょうか?

this.$nextTick を呼び出すと、実際には図の nextTick メソッドが呼び出され、非同期キュー内のコールバック関数が実行されます。先入先出の原則に従って、データの変更によってトリガーされた更新非同期キューが最初に実行されます。実行が完了すると、新しい DOM が生成されます。次に this.$nextTick のコールバック関数が実行されると、更新された DOM 要素を取得できます。

// this.$nextTick を使用して nextTick メソッドを呼び出します Vue.prototype.$nextTick = function (fn: Function) {
  nextTick(fn, this) を返します。
};

要約: Vue 非同期更新の原則

Vue のデータが変更されると、このデータに関連するすべてのウォッチャーが更新をトリガーされます。まず、すべてのウォッチャーがキューに追加されます。次に、nextTick メソッドを呼び出して非同期タスクを実行します。非同期タスクのコールバックでは、キュー内のウォッチャーをソートし、対応する DOM 更新を実行します。

Vue の DOM 非同期更新の実装に関するこの記事はこれで終わりです。Vue の DOM 非同期更新に関するより関連性の高いコンテンツについては、123WORDPRESS.COM の以前の記事を検索するか、以下の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。

以下もご興味があるかもしれません:
  • VUE は DOM を非同期的に更新します - $nextTick を使用して DOM ビューの問題を解決します
  • Vue.js ソースコードからの非同期 DOM 更新戦略と nextTick の詳細な説明
  • Vue バッチ更新 DOM 実装手順

<<:  MySQLは「order by」がどのように機能するかを簡単に理解します

>>:  NextCloud プライベート クラウド ストレージ ネットワーク ディスクの構築に関する詳細なチュートリアル

推薦する

Vueはechartsを使用して組織図を描画します

昨日、円形のプログレスバー (Vue 円形プログレスバーを参照してください) についてブログを書きま...

MySQL で期限切れのデータレコードを定期的に削除する簡単な方法

1. MySQL に接続してログインしたら、まず MySQL でイベント機能が有効になっているかどう...

3列レイアウトを実現するCSS3フレキシブルボックスフレックス

タイトルの通り、高さは既知で、左と右の列の幅は 300 ピクセル、中央は適応型です。弾性ボックス自体...

Linuxで環境変数を削除する詳細な手順

Linuxで環境変数を削除するには?unsetコマンドを使用してすぐに削除します1. Linuxクラ...

Vue ドラッグ アンド ドロップのシンプルな実装

この記事では、主に次のような Vue ドラッグ アンド ドロップの簡単な実装を紹介します。レンダリン...

Vue の下部ナビゲーション バー TabBar を実装するための非常に詳細なチュートリアル

目次プロジェクト紹介:プロジェクトディレクトリ: TabBar 効果のプレビュー: TabBar 実...

Mysql は、デッドロック問題を解決するために kill コマンドを使用します (実行中の特定の SQL ステートメントを強制終了します)。

MySQL を使用して特定のステートメントを実行すると、データ量が多いためにデッドロックが発生し、...

レスポンシブデザインについての簡単な説明

1. レスポンシブ デザインとは何ですか?レスポンシブデザインとは、ウェブサイトの開発プロセス中に、...

mysql5.7.18のインストールと初期パスワードの変更方法

CentosでのMySQLのインストールについては、以前の記事を参照してください。 Centos7....

iframe を使用して Web ページに他の Web ページを埋め込む方法

iframe の使い方:コードをコピーコードは次のとおりです。 <DIV align=cent...

Dockerコンテナでyumを呼び出すときのエラーの解決方法

dockerfile またはコンテナ内で yum を実行すると、エラーが報告され、ソースが見つかりま...

HTML特殊文字の徹底分析

HTML徹底解析(14)特殊文字 ■ よく使われる特殊文字 HTMLタグを知っていれば、特殊文字の使...

CSS の画像パスの問題に関する議論 (同じパッケージ/異なるパッケージ)

CSS ファイルでは、背景を使用する、つまり背景画像を追加する必要がある場合があります。これは通常、...

MySQL ステートメントの概要

目次1. データベースの使用を選択2. 情報を表示する3. テーブルを作成する4. データを挿入する...

js配列のfind、some、filter、reduceの違いの詳細な説明

Array の filter、find、some、reduce メソッドの違いを区別し、使用シナリオ...