仮想DOMの役割まず、仮想 DOM の出現によってどのような問題が解決されるのかを知る必要があります。仮想 DOM は、頻繁に行われる直接的な DOM 操作の効率が低い問題を解決します。では、DOM を直接操作するのはなぜ非効率的なのでしょうか? たとえば、div を作成すると、この div には多くのプロパティがあり、それを継承していることをコンソールで確認できます。特に、js を使用して DOM を操作する場合、DOM 自体は非常に複雑で、js 操作に多くの時間がかかりますが、DOM 要素自体を制御することはできません。そのため、仮想 DOM はjs が DOM を操作する問題を解決し、実際に dom 操作の数を減らします。 仮想DOMのシンプルな実装仮想 DOM は、その名前が示すように、偽の DOM です。実際の DOM はページにマウントされますが、仮想 DOM はメモリ内にあります。これには、実際の DOM をオブジェクトに抽象化し、それをメモリに保存する必要があります。このオブジェクトは次のタイプになります。 var要素 = { タグ名: 'div', 小道具: { クラス: 'ボックス' }, 子供たち: { { タグ名: 'p', 小道具: { クラス: 'p1' }, 子供達: ['私はp1です'] }, { タグ名: 'p', 小道具: { クラス: 'p2' }, 子供たち: [「私はp2です」] }, { タグ名: 'p', 小道具: { クラス: 'p3' }, 子供たち: [「私はp3です」] }, } } このようなオブジェクトを構築したい場合は、次のようにコンストラクターをカプセル化できます。 関数 Element(タグ名, props, children) { this.tagName = タグ名 this.props = 小道具 this.children = 子供 } このオブジェクトを使用して、この仮想 DOM を実際の DOM にレンダリングする必要があります。次のメソッドを記述できます。 Element.prototype.render = 関数 () { const { tagName, props, children } = this var el = document.createElement(タグ名) for (props のキー) { el.setAttribute(キー、props[キー]) } children.forEach((item) => { const childEl = (item instanceof Element) ? アイテム.レンダリング(): document.createTextNode(アイテム) el.appendChild(childEl) }) エルを返す } 最後に、このオブジェクトを作成し、render() メソッドを呼び出して、body に appendChild を追加します。 virtualDom = new Element('div', { class: 'box' }, [ とする 新しい要素('p', { クラス: 'p1' }, ['私はp1です']), 新しい要素('p', { クラス: 'p2' }, ['私はp2です']), 新しい要素('p', { クラス: 'p3' }, ['私はp3です']), ]) a = virtualDom.render() とします。 ドキュメント本体に子要素を追加します。 差分アルゴリズムまず、diffアルゴリズムの役割を理解しましょう 仮想 DOM が変更されると、メモリ内に新しい仮想 DOM が生成されます。この新しい仮想 DOM 構造を直接使用すると、レンダリングが何度も繰り返されることになります。そのため、このときに diff アルゴリズムの役割が反映されます。diff は、新しい仮想 DOM ツリーと古い仮想 DOM ツリーを比較し、違いを見つけて記録し、記録された違いを実際の DOM ツリーに適用します。 原理: diff アルゴリズムは、新しいツリーと古いツリーの深さ優先走査を実行し、各ノードに一意の識別子を追加します。 このプロセスは2つのステップに分かれています
DOMの操作は基本的に4つの種類に分けられます
以下は、このプロセスを擬似コードの形で大まかに説明します。 // diff関数、2つのツリーを比較する function diff(oldTree, newTree) { var patches = {}; // 疑似配列、差異を記録 // 4種類のノードに対してエラー判定を行う dfWork(oldTree, newTree, patches, index) パッチを返す } 関数 dfWork(oldTree, newTree, パッチ, インデックス) { 現在のパッチを [] にする if (1) { // ノードを削除する currentPatch.push() } else if (3) { // ノードのテキストを変更する currentPatch.push() } else { // ノードのプロパティを変更します。子を確認します // プロパティに対して diff アルゴリズムを実行し、変更をパッチに記録します。 currentPatch.push({ type: patch.PROPS, props: propsPatches }) // 次に、子ノードに対して diff アルゴリズムを実行する必要があります diffChildren(oldNode.children, newNode.children, index, patches, currentPatch) } } 関数 diffChildren(oldChildren, newChildren, index, patches, currentPatch) { // 子ノードに対して diff アルゴリズムを実行し、子ノードを走査し、dfWork を再帰的に呼び出して差分を取り、パッチを取得します } // 実際のDOMツリーに変更を適用する function patch(node, patches) { // ノードは古い DOM ツリーであり、変更をパッチします。 // パッチを走査し、ノードをパッチに一致させます。 } 関数applyPatch(ノード、パッチ) { // 各ノードには複数の変更がある可能性があるため、switch (patchs.type) {を走査する必要もあります。 case REPLACE: // ノードの置換 // node.render() 壊す; case REORDER: // 子ノードを移動、削除し、新しい子ノードを追加します。 壊す; ケースのPROPS: // プロパティを設定する 壊す; case TEXT: // ノードテキストを変更する // node.nodeValue 壊す; デフォルト: 壊す; } } 参考資料: 詳細な分析: 仮想 DOM アルゴリズムの実装方法 著者: livoras、組み込みソース コード。 これで、React の仮想 DOM と diff アルゴリズムに関するこの記事は終了です。React の仮想 DOM と diff アルゴリズムに関するより関連性の高いコンテンツについては、123WORDPRESS.COM の以前の記事を検索するか、以下の関連記事を引き続き参照してください。今後も 123WORDPRESS.COM を応援していただければ幸いです。 以下もご興味があるかもしれません:
|
>>: MySQL の binlog_format モードと設定の詳細な分析
1. バックアップスクリプトを書く 著者:www.yumi-info.com 日付:20171222...
背景何が起こったかというと、Luzhu は偶然、宇宙で最高の外部スピーカーを備えた携帯電話について知...
当初の意図は、element-ui の $notify 通知をコンポーネントにカプセル化することでし...
1. maxPostSize を設定する理由は何ですか? tomcat コンテナには送信データのサイ...
CentOS7 のデフォルトのファイアウォールは iptables ではなく、firewalle で...
1. mysqlbackup の紹介mysqlbackup は、MySQL Enterprise B...
目次MySQL を使い始めるMySQL 管理6. MySQL サーバーを起動および停止します。 7....
Docker 公式ドキュメントからの翻訳、原文: https://docs.docker.com/n...
序文インターセプター最近のフロントエンド フレームワークでは、インターセプターは基本的に非常に基本的...
Linux に zip 解凍機能をインストールする通常、 zip コマンドは Linux サーバーに...
問題の起源私がタイトルの番号付けの問題に初めて注目したのは、学部の論文を書いていた頃まで遡ります。当...
最近、Oracle、MySQL、SQL Server 2005 のデータ ページング クエリについて...
MySQL の仕様によっては、テーブル作成仕様にすべてのフィールドが空であってはならないという要件を...
ウェブサイトを開発する場合、データを保存するためにデータベースを使用する必要があることがよくあります...
01. 概要絶対パスと相対パスはシェル環境でよく使用され、それぞれに独自の用途があります。相対パスの...