序文現在主流のフレームワークである Vue と React はどちらも Virtual Dom を通じて実装されており、Virtual Dom テクノロジーによってページのレンダリング効率が向上します。 Vue ではテンプレートに HTML コードを記述し、React では内部レンダリング関数に HTML コードを記述します。この関数が jsx を通じてコンパイルされると、実際には h 関数が出力されます。これが仮想 DOM です。以下は、実際の DOM をレンダリングする仮想 DOM と更新メソッドの簡単な実装です。 ターゲット主に以下の3つの機能を実現します。
最初のステップ:bodyタグ内にid appを持つノードを作成します。このノードに後で仮想ノードをマウントし、renderer.jsを使用して上記3つの機能を実装します。 <本文> <div id="アプリ"></div> <script src="./renderer.js"></script> </本文> ステップ2:h 関数を記述して、tag (タグ要素)、props (プロパティ オブジェクト)、children (子ノード) を返します。簡単に言えば、仮想 Dom は通常の JavaScript オブジェクトです。 // レンダラー.js const h = (タグ、プロパティ、子) => { 戻る { タグ、 小道具、 子供たち } } それでは、この h 関数を使用して、次のコードが何を出力するか簡単に見てみましょう。 const vdom = h("div", {クラス: "header"}, [ h("h2", null, "Hello World"), h("h2", {id: 0}, h("span", null, "啦啦啦啦啦")) // props に値がない場合、null を渡す必要があり、省略することはできません]); コンソールログ(vdom); 下の図からわかるように、h 関数を通じて、ツリー ノードを形成する仮想 Dom である JavaScript オブジェクトが返されます。 では、この vnode を実際のノードにマウントするにはどうすればよいでしょうか?それではステップ3を見てみましょう。 ステップ3:まず、2 つのパラメータを渡す必要があるマウント関数を作成します。1 つ目は h 関数で返した vnode で、2 つ目のパラメータはこれらの vnode をマウントするノードです。コードを見てみましょう。 const マウント = (vnodes, アプリ) => { // vnodes のタグ値 ("div", "h2") を通じてノードを作成します。 // また、将来の更新や追加などを容易にするために、vnodes オブジェクトに実際の DOM を保存します。 const el = vnodes.el = document.createElement(vnodes.tag); // このノードを取得した後、props 値を判断してプロパティを追加します if (vnodes.props) { for (let key in vnodes.props) { // ここでは、props 内のキー値を取得した後、判断を行います。let value = vnodes.props[key]; キーが「on」で始まる場合 // たとえば、ユーザーが onClick="changeData" と記述した場合、イベント リスナー関数として処理されます el.addEventListener(key.slice(2).toLowerCase(), value) } それ以外 { el.setAttribute(キー、値) } // 境界処理のための命令やv-ifなどの判断が下にあります} } // props を処理した後、最後のノードは Children です if (vnodes.children) { if (typeof vnodes.children === 'string') { // これが文字列型の場合、ノードに直接追加できます el.textContent = vnodes.children } それ以外 { // このケースは配列型で、子ノードを含み、トラバーサルを通じて子ノードを生成します vnodes.children.forEach(vnode => { // 子ノードを現在のノードに再帰的にマウントします mount(vnode, el) }) } } //最後に、この実際のノードを、app.appendChild(el); で渡したアプリ ノードにマウントします。 } const app = document.querySelector("#app") マウント(vdom、アプリ) mount 関数を使用してマウントした場合の実際の効果を見てみましょう。 これまで、仮想 DOM を通じて実際の DOM を作成してきました。これらの DOM を Vue で更新するにはどうすればよいでしょうか。次に、パッチ関数 (update) を作成します。 ステップ4:パッチ関数を通じて、新しい仮想 DOM と古い仮想 DOM の 2 つのパラメータ (vnodes1、vnodes2) を渡す必要があります。新しい仮想 DOM と古い仮想 DOM を比較することで、更新するノードを指定できます。 (ここではキー値は考慮されません。キー値を参照する必要がある場合は、リンクを確認してください: https://www.jb51.net/article/219078.htm) //patch 関数 n1: 古いノード、n2: 新しいノード // vue ソースコードでは、古い vnode と新しい vnode はそれぞれ n1 と n2 で表されます。const patch = (n1, n2) => { // 上記では、マウント関数を通じてノード属性 el を n2 に追加し、それを n2 にバインドしました。const el = n2.el = n1.el // まず、2つのタグから始めます。if (n1.tag == n2.tag) { // n1とn2は同じタグを持っているので、プロパティを比較します 定数 n1Props = n1.props || {}; 定数 n2Props = n2.props || {}; // n1 と n2 からそれぞれプロパティを取得して比較します for (let key in n2Props) { // n2 のすべてのキーを取り出し、n2 のキー値が n1 のキー値と同じかどうかを確認します。const n1Value = n1Props[key] || ''; const n2Value = n2Props[キー] || ''; (n1値 !== n2値)の場合{ キーが「on」で始まる場合 // たとえば、ユーザーが onClick="changeData" と記述した場合、イベント リスナー関数として処理されます el.addEventListener(key.slice(2).toLowerCase(), n2Value) } それ以外 { el.setAttribute(キー、n2値) } } // 同じ場合は処理は行われません} for (let key in n1Props) { const oldValue = n1Props[キー]; if (!(n2Propsのキー)) { キーが「on」で始まる場合 el.removeEventListener(キー.slice(2).toLowerCase(), 古い値) } それ以外 { el.removeAttribute(キー) } } } } それ以外 { // タグが異なる場合は、n1 の親ノードを取得します。const n1Parent = n1.el.parentElement; // removeChild によって親ノードから古いノードを削除し、n2 を親ノードにマウントします。n1Parent.removeChild(n1.el); //n1.el はマウント関数によってオブジェクトに追加された実際の DOM ノードです。mount(n2, n1Parent) } // 最後に、比較的複雑な子を処理します。 // 子は文字列または配列になる可能性があるため、最初に文字列を処理する方法を見てみましょう。 const n1Children = n1.children || []; 定数 n2Children = n2.children || []; if (typeof n2Children === "文字列") { // 新しいノードのコンテンツが文字列の場合は、innerhtml を直接使用して置き換えます。el.innerHtml = n2Children; } それ以外 { // 次の状況は、n2.children が配列の場合です if (typeof n1.children === "string") { // n1.children は文字列、n2.children は配列 el.innerHtml = ''; // まずノードの内容を確認し、次に新しい内容を追加します mount(n2.children, el) } それ以外 { // 両方が配列型の場合、キー値はここでは考慮されません const minLength = Math.min(n1Children.length, n2Children.length); (i = 0 ; i < minLength ; i++ とします) { パッチ(n1Children[i], n2Children[i]); } (n2Children.length > n1Children.length) の場合 { n2Children.slice(minLength).forEach(item => { マウント(アイテム、エル) }) } (n2Children.length < n1Children.length) の場合 { n1Children.slice(minLength).forEach(item => { el.removeChild(アイテム.el) }) } } } } 上記は patch 関数の単純な実装であり、実際には diff アルゴリズムと呼ばれるものです (もちろん、ここではキー値は考慮されておらず、順番に比較できるのは 2 つだけです)。比較は同じレベルで行われます。次に、更新が成功するかどうかをシミュレートして実証してみましょう。 const vdom = h("div", {クラス: "header"}, [ h("h2", null, "Hello World"), h("h2", {id: 0}, [h("span", null, "啦啦啦啦")]) // props に値がない場合、null を渡す必要があり、省略することはできません]); const app = document.querySelector("#app") マウント(vdom、アプリ) setTimeout(()=> { // 3秒後に新しいVnodeと古いVnodeをパッチに渡す const vdom1 = h("div", {クラス: "header"}, [ h("h3", null, "Hello World"), h("span", null, "哈哈哈哈") ]) パッチ(vdom, vdom1) },3000) 下の図から、仮想 DOM 更新ノードがシンプルに実装されていることがわかります。 要約する仮想 Dom を実装して実際のノードを生成し、パッチを通じて更新するだけです。ソースコードをもう一度見てみると、Vue のレンダラーがどのように実装されているかがよりよく理解できるようになります。 mini-vueレンダリングの簡単な実装に関するこの記事はこれで終わりです。より関連性の高いmini-vueレンダリングコンテンツについては、123WORDPRESS.COMの過去の記事を検索するか、以下の関連記事を引き続き閲覧してください。皆様、今後とも123WORDPRESS.COMを応援してください。 以下もご興味があるかもしれません:
|
<<: Ubuntu 上で WebRTC ベースの複数人ビデオチャット サービスを構築するための詳細なコード
>>: MySQLにおけるテーブルインデックスの定義方法と導入
W3Cschoolではこのように説明しています<meta> 要素は、検索エンジン向けの説...
コードをコピーコードは次のとおりです。 wmode パラメータ:透過モード: z-indexを使用し...
この記事では、MySQL 8.0.15の詳細なインストールと使用方法のチュートリアルを参考までに紹介...
目次1. 問題のあるSQL文たとえば、次の図のような質問をした人がいました。 問題は次のように要約で...
目次プロトタイプを理解するプロトタイプオブジェクトを理解するインスタンスプロパティとプロトタイププロ...
1. Linuxグループの基本紹介Linux では、すべてのユーザーはグループに所属する必要があり、...
今日は、CSS3 の transition-delay 属性のデフォルト値 0 に単位がないのは無効...
重要なのは、ローカルサーバーに書き込み権限がないことですキーはここにあります(アクセス拒否)。私は肯...
このスクリプトは、nginxの起動、停止、再起動の操作を満たすことができます。 #!/bin/bas...
表示する svg 画像を追加すると、React はファイルが見つからないというメッセージを表示します...
この記事では、モバイル端末を一度に1画面ずつ上下にスライドさせるためのJSの具体的なコードを参考まで...
テキストシャドウ text-shadow プロパティの効果: 1. 右下隅の影、左下隅の影、左上隅の...
この記事では主に、次のように共有されるネイティブ JS 音楽プレーヤーのサンプル コードを紹介します...
シナリオ: docker で tomcat を起動すると (Alibaba Cloud からダウンロ...
TypeScript バンドルwebpack 統合通常、実際の開発では、ビルド ツールを使用してコー...