diffの対象は仮想domです

Apr 08, 2018 pm 05:55 PM
diff バーチャル

今回、持ってきた diff のオブジェクトは仮想 dom です。 diff 仮想 dom オブジェクト を使用する際の 注意事項について、実際の事例を見てみましょう。

仮想dom

diffアルゴリズムは、まずdiffのオブジェクトが仮想domであり、実際のdomの更新はdiffアルゴリズムの結果であるという概念を明確にする必要があります

Vnode基本クラス

 constructor (
  。。。
 ) {
  this.tag = tag
  this.data = data
  this.children = children
  this.text = text
  this.elm = elm
  this.ns = undefined
  this.context = context
  this.fnContext = undefined
  this.fnOptions = undefined
  this.fnScopeId = undefined
  this.key = data && data.key
  this.componentOptions = componentOptions
  this.componentInstance = undefined
  this.parent = undefined
  this.raw = false
  this.isStatic = false
  this.isRootInsert = true
  this.isComment = false
  this.isCloned = false
  this.isOnce = false
  this.asyncFactory = asyncFactory
  this.asyncMeta = undefined
  this.isAsyncPlaceholder = false
 }
ログイン後にコピー
のこの部分このコードは主に更新用です。 diff アルゴリズムの特定の diff 属性

の意味を知ることは良いことです。 もちろん、vnode インスタンス 全体のプロセス

のコア機能は patch 関数です。

    isUndef判定(unknownかnullか)
  • //空のマウント(おそらくコンポーネントとして)、新しいルート要素を作成createElm(vnode,insertedVnodeQueue) ここで、作成されたノードが挿入されていないことがわかります1つずつですが、統合バッチ処理のために
  • キュー

    に入れられます

  • コア関数sameVnode
  • function sameVnode (a, b) {
     return (
      a.key === b.key && (
       (
        a.tag === b.tag &&
        a.isComment === b.isComment &&
        isDef(a.data) === isDef(b.data) &&
        sameInputType(a, b)
       ) || (
        isTrue(a.isAsyncPlaceholder) &&
        a.asyncFactory === b.asyncFactory &&
        isUndef(b.asyncFactory.error)
       )
      )
     )
    }
    ログイン後にコピー
  • は、2つのノードのキー、タグ(ラベル)、データを直接比較する外部比較関数です(注)ここでのデータは VNodeData を指します)、入力は直接比較されます。
export interface VNodeData {
 key?: string | number;
 slot?: string;
 scopedSlots?: { [key: string]: ScopedSlot };
 ref?: string;
 tag?: string;
 staticClass?: string;
 class?: any;
 staticStyle?: { [key: string]: any };
 style?: object[] | object;
 props?: { [key: string]: any };
 attrs?: { [key: string]: any };
 domProps?: { [key: string]: any };
 hook?: { [key: string]: Function };
 on?: { [key: string]: Function | Function[] };
 nativeOn?: { [key: string]: Function | Function[] };
 transition?: object;
 show?: boolean;
 inlineTemplate?: {
  render: Function;
  staticRenderFns: Function[];
 };
 directives?: VNodeDirective[];
 keepAlive?: boolean;
}
ログイン後にコピー

これにより、2 つのノードにさらなる比較値があるかどうかが確認され、そうでない場合は直接置換されます

置換プロセスは主に createElm 関数であり、もう 1 つは oldVNode を破棄することです

// destroy old node
    if (isDef(parentElm)) {
     removeVnodes(parentElm, [oldVnode], 0, 0)
    } else if (isDef(oldVnode.tag)) {
     invokeDestroyHook(oldVnode)
    }
ログイン後にコピー

簡略化して挿入プロセスノードのタイプを決定し、それを個別に呼び出すことです

createComponent (子があるかどうかを決定し、それを再帰的に呼び出します)

createComment

createTextNode

作成後に挿入関数を使用します

その後、次のことを行う必要がありますハイドレート関数を使用して、仮想 dom と実際の dom をマッピングします

function insert (parent, elm, ref) {
  if (isDef(parent)) {
   if (isDef(ref)) {
    if (ref.parentNode === parent) {
     nodeOps.insertBefore(parent, elm, ref)
    }
   } else {
    nodeOps.appendChild(parent, elm)
   }
  }
 }
ログイン後にコピー

core 関数

 function patchVnode (oldVnode, vnode, insertedVnodeQueue, removeOnly) {
  if (oldVnode === vnode) {
   return
  }
  const elm = vnode.elm = oldVnode.elm
  if (isTrue(oldVnode.isAsyncPlaceholder)) {
   if (isDef(vnode.asyncFactory.resolved)) {
    hydrate(oldVnode.elm, vnode, insertedVnodeQueue)
   } else {
    vnode.isAsyncPlaceholder = true
   }
   return
  }
  if (isTrue(vnode.isStatic) &&
   isTrue(oldVnode.isStatic) &&
   vnode.key === oldVnode.key &&
   (isTrue(vnode.isCloned) || isTrue(vnode.isOnce))
  ) {
   vnode.componentInstance = oldVnode.componentInstance
   return
  }
  let i
  const data = vnode.data
  if (isDef(data) && isDef(i = data.hook) && isDef(i = i.prepatch)) {
   i(oldVnode, vnode)
  }
  const oldCh = oldVnode.children
  const ch = vnode.children
  if (isDef(data) && isPatchable(vnode)) {
   for (i = 0; i < cbs.update.length; ++i) cbs.update[i](oldVnode, vnode)
   if (isDef(i = data.hook) && isDef(i = i.update)) i(oldVnode, vnode)
  }
  if (isUndef(vnode.text)) {
   if (isDef(oldCh) && isDef(ch)) {
    if (oldCh !== ch) updateChildren(elm, oldCh, ch, insertedVnodeQueue, removeOnly)
   } else if (isDef(ch)) {
    if (isDef(oldVnode.text)) nodeOps.setTextContent(elm, &#39;&#39;)
    addVnodes(elm, null, ch, 0, ch.length - 1, insertedVnodeQueue)
   } else if (isDef(oldCh)) {
    removeVnodes(elm, oldCh, 0, oldCh.length - 1)
   } else if (isDef(oldVnode.text)) {
    nodeOps.setTextContent(elm, &#39;&#39;)
   }
  } else if (oldVnode.text !== vnode.text) {
   nodeOps.setTextContent(elm, vnode.text)
  }
  if (isDef(data)) {
   if (isDef(i = data.hook) && isDef(i = i.postpatch)) i(oldVnode, vnode)
  }
 }
ログイン後にコピー

const el = vnode.el = oldVnode.el これは非常に重要なステップです。vnode.el に現在の実際の dom を参照させます。 dom が変更されると、vnode.el も同期して変更されます。

    2つの参照が一致しているか比較してください
  1. その後asyncFactoryが何をしているのか分からないので、理解するのが難しいです
  2. Static

    ノード比較キー、再レンダリングは行われませんそれらが同じである場合は、直接実行してください。componentInstance をコピーします (コマンドがここで有効になると)

  3. vnode がテキスト ノードまたは注釈ノードであるが、vnode.text != oldVnode.text の場合は、テキストを更新するだけで済みます。 vnode.elm の内容
  4. children の比較
    oldVnode のみに子ノードがある場合は、これらのノードを削除します
  • vnode のみに子ノードがある場合は、これらの子ノードを作成します。oldVnode がtext ノードに vnode.elm を置きます テキストが空の文字列
  • に設定されている場合、updateChildren が更新されます
  • oldVnode も vnode も子ノードを持たないが、oldVnode がテキスト ノードまたはコメント ノードの場合は、vnode.elm を追加します。テキストは空の文字列に設定されます
  • updateChildren

この部分の焦点は依然としてアルゴリズム全体にあります

最初の 4 つのポインター、oldStart、oldEnd、newStart 、newEnd、2 つの配列、oldVnode、Vnode。

function updateChildren (parentElm, oldCh, newCh, insertedVnodeQueue, removeOnly) {
  let oldStartIdx = 0
  let newStartIdx = 0
  let oldEndIdx = oldCh.length - 1
  let oldStartVnode = oldCh[0]
  let oldEndVnode = oldCh[oldEndIdx]
  let newEndIdx = newCh.length - 1
  let newStartVnode = newCh[0]
  let newEndVnode = newCh[newEndIdx]
  let oldKeyToIdx, idxInOld, vnodeToMove, refElm
  while (oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx) {
   if (isUndef(oldStartVnode)) {
    oldStartVnode = oldCh[++oldStartIdx] // Vnode has been moved left
   } else if (isUndef(oldEndVnode)) {
    oldEndVnode = oldCh[--oldEndIdx]
   } else if (sameVnode(oldStartVnode, newStartVnode)) {
    patchVnode(oldStartVnode, newStartVnode, insertedVnodeQueue)
    oldStartVnode = oldCh[++oldStartIdx]
    newStartVnode = newCh[++newStartIdx]
   } else if (sameVnode(oldEndVnode, newEndVnode)) {
    patchVnode(oldEndVnode, newEndVnode, insertedVnodeQueue)
    oldEndVnode = oldCh[--oldEndIdx]
    newEndVnode = newCh[--newEndIdx]
   } else if (sameVnode(oldStartVnode, newEndVnode)) { // Vnode moved right
    patchVnode(oldStartVnode, newEndVnode, insertedVnodeQueue)
    canMove && nodeOps.insertBefore(parentElm, oldStartVnode.elm, nodeOps.nextSibling(oldEndVnode.elm))
    oldStartVnode = oldCh[++oldStartIdx]
    newEndVnode = newCh[--newEndIdx]
   } else if (sameVnode(oldEndVnode, newStartVnode)) { // Vnode moved left
    patchVnode(oldEndVnode, newStartVnode, insertedVnodeQueue)
    canMove && nodeOps.insertBefore(parentElm, oldEndVnode.elm, oldStartVnode.elm)
    oldEndVnode = oldCh[--oldEndIdx]
    newStartVnode = newCh[++newStartIdx]
   } else {
    if (isUndef(oldKeyToIdx)) oldKeyToIdx = createKeyToOldIdx(oldCh, oldStartIdx, oldEndIdx)
    idxInOld = isDef(newStartVnode.key)
     ? oldKeyToIdx[newStartVnode.key]
     : findIdxInOld(newStartVnode, oldCh, oldStartIdx, oldEndIdx)
    if (isUndef(idxInOld)) { // New element
     createElm(newStartVnode, insertedVnodeQueue, parentElm, oldStartVnode.elm, false, newCh, newStartIdx)
    } else {
     vnodeToMove = oldCh[idxInOld]
     if (sameVnode(vnodeToMove, newStartVnode)) {
      patchVnode(vnodeToMove, newStartVnode, insertedVnodeQueue)
      oldCh[idxInOld] = undefined
      canMove && nodeOps.insertBefore(parentElm, vnodeToMove.elm, oldStartVnode.elm)
     } else {
      // same key but different element. treat as new element
      createElm(newStartVnode, insertedVnodeQueue, parentElm, oldStartVnode.elm, false, newCh, newStartIdx)
     }
    }
    newStartVnode = newCh[++newStartIdx]
   }
  }
  if (oldStartIdx > oldEndIdx) {
   refElm = isUndef(newCh[newEndIdx + 1]) ? null : newCh[newEndIdx + 1].elm
   addVnodes(parentElm, refElm, newCh, newStartIdx, newEndIdx, insertedVnodeQueue)
  } else if (newStartIdx > newEndIdx) {
   removeVnodes(parentElm, oldCh, oldStartIdx, oldEndIdx)
  }
 }
ログイン後にコピー

ループ比較のいくつかの状況と処理 (以下の ++ -- すべてインデックスの ++ を参照します --) 比較は比較対象のノードです。この比較では、sameVnode 関数が使用されます。これは当てはまりません

ループ全体が終了しないための条件 oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx

oldStart === newStart, oldStart++ newStart++
  1. oldEnd === newEnd 、 oldEnd-- newEnd--
  2. oldStart === newEnd、oldStart はキューの最後に挿入されます oldStart++ newEnd--
  3. oldEnd === newStart、oldEnd はキューの先頭に挿入されます oldEnd- - 新しいスタート++
  4. 剩下的所有情况都走这个处理简单的说也就两种处理,处理后newStart++

  • newStart在old中发现一样的那么将这个移动到oldStart前

  • 没有发现一样的那么创建一个放到oldStart之前

循环结束后并没有完成

还有一段判断才算完

if (oldStartIdx > oldEndIdx) {
   refElm = isUndef(newCh[newEndIdx + 1]) ? null : newCh[newEndIdx + 1].elm
   addVnodes(parentElm, refElm, newCh, newStartIdx, newEndIdx, insertedVnodeQueue)
  } else if (newStartIdx > newEndIdx) {
   removeVnodes(parentElm, oldCh, oldStartIdx, oldEndIdx)
  }

简单的说就是循环结束后,看四个指针中间的内容,old数组中和new数组中,多退少补而已

相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!

推荐阅读:

JS的EventEmitter使用步奏详解

怎么用Vue导出excel表格功能

怎么在微信小程序里做出全局搜索代码高亮提醒

以上がdiffの対象は仮想domですの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

Microsoft Wi-Fi Direct 仮想アダプター: 何をするものですか? Microsoft Wi-Fi Direct 仮想アダプター: 何をするものですか? Jun 29, 2023 pm 12:33 PM

Microsoft Wi-Fi Direct 仮想アダプターが PC 上で何をするのか疑問に思われるかもしれません。このネットワーク アダプターは Microsoft 製で完全に安全ですので、ご安心ください。ただし、アダプターがアクティビティを台無しにしており、そのままにしておく価値があるかどうか疑問に思っている場合は、このガイドで知っておくべきすべてのことがわかります。 Microsoft Wi-Fi Direct 仮想アダプターは何をしますか?名前が示すように、Microsoft Wi-Fi Direct 仮想アダプターは、PC をワイヤレス ホットスポットにするのに役立ちます。これにより、他のコンピュータがあなたの PC に接続してインターネットにアクセスできるようになります。これは、ワイヤレス ネットワーク アダプターを仮想化することで実現されます。このようにして、1 つの物理ワイヤレス アダプタが 2 つの仮想ワイヤレス アダプタに変換されます。

スタンフォード大学の「バーチャルタウン」と「ウエストワールド」から着想を得た25種類のAIエージェントのソースコードが公開 スタンフォード大学の「バーチャルタウン」と「ウエストワールド」から着想を得た25種類のAIエージェントのソースコードが公開 Aug 11, 2023 pm 06:49 PM

「ウエストワールド」に慣れている視聴者は、このショーが未来の世界にある巨大なハイテク成人向けテーマパークを舞台としていることを知っています。ロボットは人間と同様の行動能力を持ち、見聞きしたものを記憶し、核となるストーリーラインを繰り返すことができます。これらのロボットは毎日リセットされ、初期状態に戻ります。スタンフォード大学の論文「Generative Agents: Interactive Simulacra of Human Behavior」の発表後、このシナリオは映画やテレビシリーズに限定されなくなりました。AI はこれを再現することに成功しました。スモールヴィルの「バーチャルタウン」のシーン》概要図用紙アドレス:https://arxiv.org/pdf/2304.03442v1.pdf

svn diff を vimdiff に置き換えます: コードを比較するためのツール svn diff を vimdiff に置き換えます: コードを比較するためのツール Jan 09, 2024 pm 07:54 PM

Linux では、svndiff コマンドを直接使用してコードの変更を表示するのは非常に難しいため、インターネット上でより良い解決策を探しました。それは、特に使用に慣れている人向けに、svndiff のコード表示ツールとして vimdiff を使用することです。 vim. とても便利です。 svndiff コマンドを使用して特定のファイルの変更を比較する場合、たとえばコマンド $svndiff-r4420ngx_http_limit_req_module.c を実行すると、実際にはコマンド -u-Lngx_http_limit_req_module.c がデフォルトの差分プログラムに送信されます。 (改訂 4420)-Lngx_

2025年の暗号通貨サークルのトップ10仮想通貨取引プラットフォーム 2025年の暗号通貨サークルのトップ10仮想通貨取引プラットフォーム Mar 12, 2025 pm 05:27 PM

2025年の暗号通貨サークルのトップ10の仮想取引プラットフォーム:高い流動性、豊富な製品である。 6。コインベース、米国の主要な交換、使いやすいコンプライアンス。

ネットワークケーブルに沿って登るのが現実となり、対話を通じてリアルな表現や動きを生成できるAudio2Photoreal ネットワークケーブルに沿って登るのが現実となり、対話を通じてリアルな表現や動きを生成できるAudio2Photoreal Jan 12, 2024 am 09:03 AM

冷たい電話画面越しに友人とチャットしているときは、相手の声の調子を推測する必要があります。彼が話すとき、彼の表情や行動さえもあなたの心に現れます。もちろんビデオ通話ができれば一番良いのですが、実際はいつでもビデオ通話ができるわけではありません。遠く離れた友人とチャットする場合、それは冷たい画面のテキストや表情のないアバターではなく、リアルでダイナミックで表現力豊かなデジタル仮想人物です。この仮想人物は、友人の笑顔、目、微妙な体の動きさえも完璧に再現することができます。もっと優しくて温かい気持ちになれるでしょうか?これはまさに「ネットワークケーブルに沿って這ってあなたを見つけます」という文を体現しています。これはSFの空想ではなく、現実に実現可能な技術です。フェイシャルテーブル

アップル電話でダウンロードする仮想コイン アップル電話でダウンロードする仮想コイン Feb 21, 2025 pm 05:57 PM

仮想通貨アプリケーションは、最新の投資と財務管理のための重要なツールになっています。この記事では、仮想通貨アプリケーションの利点と短所を詳細に調査し、Apple携帯電話のユーザーが利用できる最適なアプリケーションに焦点を当てています。これらのアプリの機能、セキュリティ対策、ユーザーエクスペリエンスについて説明して、読者が特定のニーズを満たす最高の仮想通貨アプリを取得するための情報に基づいた選択を行うのに役立ちます。

通常の仮想通貨取引アプリ最新の10通貨取引プラットフォームは何ですか? 通常の仮想通貨取引アプリ最新の10通貨取引プラットフォームは何ですか? Feb 21, 2025 pm 09:09 PM

この記事では、世界をリードする暗号通貨交換の包括的な評価を提供します。 OKX、Binance、Gate.io、およびBitgetはすべて、優れた機能と利点のためにリストのトップです。 OKXは、低い取引手数料、高度な取引ツール、豊富な教育リソースを備えた世界最大の交換であり、幅広い暗号通貨の選択とデリバティブサービスを提供しています。 Gate.ioは、包括的な投資ツールと低い取引手数料で知られています。 Bitgetは、デリバティブ取引に焦点を当て、柔軟な取引メカニズムと革新的なプラットフォームを提供します。

仮想コインを採掘してお金を稼ぐことができますか?それは本当ですか? 仮想コインを採掘してお金を稼ぐことができますか?それは本当ですか? Mar 04, 2025 am 07:09 AM

仮想通貨採掘:機会と課題は仮想通貨マイニングで共存します。つまり、コンピューターアルゴリズムを使用して、仮想通貨を取得するための複雑な数学的問題を解決し、ネットワークセキュリティを維持し、新しいコインを安定させることに重要です。ただし、採掘コストが上昇するにつれて、収益性は非常に疑問視されています。この記事では、仮想通貨採掘の利益の可能性と、そのリターンに影響を与える重要な要因について詳しく説明します。マイニング利益分析マイニングは、ブロックチェーンネットワークのコンピューティングと検証に参加することにより、仮想通貨の報酬を受け取ります。クラウドマイニングなどのテクノロジーの上昇により、参加のしきい値が低下しました。マイニングは、収入の比較的安定した源泉を提供できますが、マイニングマシンが正常に動作しており、電源が十分である場合にのみです。さらに、仮想通貨の価格は劇的に変動し、高い収益をもたらす可能性があり、また作成する可能性があります

See all articles