国产av日韩一区二区三区精品,成人性爱视频在线观看,国产,欧美,日韩,一区,www.成色av久久成人,2222eeee成人天堂

Maison interface Web js tutoriel Comment utiliser l'algorithme Diff dans Vue 2.5

Comment utiliser l'algorithme Diff dans Vue 2.5

Jun 23, 2018 pm 05:00 PM
diff vue algorithme

Cet article analysera le Virtual Dom utilisé dans la version Vue 2.5.3. updataChildren est au c?ur de l'algorithme Diff, cet article effectue donc une analyse graphique de updataChildren. Permettez-moi de partager avec vous l'algorithme Diff de Vue 2.5 à travers cet article. Les amis qui en ont besoin peuvent s'y référer

DOM est "intrinsèquement lent", donc tous les principaux frameworks frontaux fournissent des moyens d'optimiser les opérations DOM. Dans Angular, il s'agit d'une vérification de valeur sale. React a d'abord proposé Virtual Dom, et Vue2.0 a également ajouté Virtual Dom, qui est similaire à React.

Cet article analysera le Virtual Dom utilisé dans la version Vue 2.5.3.

updataChildren est le c?ur de l'algorithme Diff, cet article effectue donc une analyse graphique de updataChildren.

Objet 1.VNode

Une instance de VNode contient les attributs suivants. Cette partie du code se trouve dans src/core/vdom/vnode. .js ri

export default class VNode {
 tag: string | void;
 data: VNodeData | void;
 children: ?Array<VNode>;
 text: string | void;
 elm: Node | void;
 ns: string | void;
 context: Component | void; // rendered in this component&#39;s scope
 key: string | number | void;
 componentOptions: VNodeComponentOptions | void;
 componentInstance: Component | void; // component instance
 parent: VNode | void; // component placeholder node

 // strictly internal
 raw: boolean; // contains raw HTML? (server only)
 isStatic: boolean; // hoisted static node
 isRootInsert: boolean; // necessary for enter transition check
 isComment: boolean; // empty comment placeholder?
 isCloned: boolean; // is a cloned node?
 isOnce: boolean; // is a v-once node?
 asyncFactory: Function | void; // async component factory function
 asyncMeta: Object | void;
 isAsyncPlaceholder: boolean;
 ssrContext: Object | void;
 functionalContext: Component | void; // real context vm for functional nodes
 functionalOptions: ?ComponentOptions; // for SSR caching
 functionalScopeId: ?string; // functioanl scope id support
  • tag?: le nom de la balise du n?ud actuel

  • data?: l'objet de données du n?ud actuel S'il vous pla?t. reportez-vous à vue pour des champs spécifiques. La définition de VNodeData dans le code source types/vnode.d.ts

  • children?: type de tableau, y compris les n?uds enfants du n?ud actuel

  • text : Le texte du n?ud actuel. Généralement, les n?uds de texte ou les n?uds de commentaire auront cet attribut

  • elm : Le vrai n?ud dom correspondant au courant. n?ud virtuel

  • ns?: espace de noms du n?ud

  • contexte?: portée de compilation

  • fonctionnelContext?: portée de composant fonctionnel

  • key?: L'attribut clé du n?ud, utilisé comme identifiant du n?ud, qui est bénéfique pour l'optimisation des correctifs

  • composantOptions?: informations sur les options utilisées lors de la création d'une instance de composant

  • enfant?: l'instance de composant correspondant au n?ud actuel

  • parent?: le n?ud d'espace réservé de le composant

  • raw : raw html

  • isStatic : Identification du n?ud statique

  • isRootInsert : S'il faut insérer en tant que n?ud racine, par

  • isComment?:?si le n?ud actuel est un n?ud de commentaire

  • isCloned?: si le n?ud actuel est un n?ud clone

  • isOnce?: indique si le n?ud actuel a la directive v-once

2. ??>

VNode peut être compris comme une classe de base de VueVirtual Dom, les instances de VNnode générées via le constructeur de VNode peuvent appartenir aux catégories suivantes?:

  • EmptyVNode : n?ud de commentaire sans contenu

  • TextVNode?: n?ud de texte

  • ElementVNode?: n?ud d'élément commun

  • ComponentVNode?: n?ud de composant

  • CloneVNode?: cloner un n?ud, vous pouvez Il s'agit de n'importe quel type de n?ud ci-dessus. La seule différence est que l'attribut isCloned est vrai

  • .

3.Analyse du code source de Create-Element

Cette partie du code est dans src/core/vdom/create-element.js, je viens de collez le code et ajoutez mes commentaires

export function createElement (
 context: Component,
 tag: any,
 data: any,
 children: any,
 normalizationType: any,
 alwaysNormalize: boolean
): VNode {
 // 兼容不傳data的情況
 if (Array.isArray(data) || isPrimitive(data)) {
 normalizationType = children
 children = data
 data = undefined
 }
 // 如果alwaysNormalize是true
 // 那么normalizationType應(yīng)該設(shè)置為常量ALWAYS_NORMALIZE的值
 if (isTrue(alwaysNormalize)) {
 normalizationType = ALWAYS_NORMALIZE
 }
 // 調(diào)用_createElement創(chuàng)建虛擬節(jié)點(diǎn)
 return _createElement(context, tag, data, children, normalizationType)
}

export function _createElement (
 context: Component,
 tag?: string | Class<Component> | Function | Object,
 data?: VNodeData,
 children?: any,
 normalizationType?: number
): VNode {

 /**
 * 如果存在data.__ob__,說(shuō)明data是被Observer觀察的數(shù)據(jù)
 * 不能用作虛擬節(jié)點(diǎn)的data
 * 需要拋出警告,并返回一個(gè)空節(jié)點(diǎn)
 *
 * 被監(jiān)控的data不能被用作vnode渲染的數(shù)據(jù)的原因是:
 * data在vnode渲染過(guò)程中可能會(huì)被改變,這樣會(huì)觸發(fā)監(jiān)控,導(dǎo)致不符合預(yù)期的操作
 */
 if (isDef(data) && isDef((data: any).__ob__)) {
 process.env.NODE_ENV !== &#39;production&#39; && warn(
  `Avoid using observed data object as vnode data: ${JSON.stringify(data)}\n` +
  &#39;Always create fresh vnode data objects in each render!&#39;,
  context
 )
 return createEmptyVNode()
 }
 // object syntax in v-bind
 if (isDef(data) && isDef(data.is)) {
 tag = data.is
 }
 if (!tag) {
 // 當(dāng)組件的is屬性被設(shè)置為一個(gè)falsy的值
 // Vue將不會(huì)知道要把這個(gè)組件渲染成什么
 // 所以渲染一個(gè)空節(jié)點(diǎn)
 // in case of component :is set to falsy value
 return createEmptyVNode()
 }
 // key為非原始值警告
 // warn against non-primitive key
 if (process.env.NODE_ENV !== &#39;production&#39; &&
 isDef(data) && isDef(data.key) && !isPrimitive(data.key)
 ) {
 warn(
  &#39;Avoid using non-primitive value as key, &#39; +
  &#39;use string/number value instead.&#39;,
  context
 )
 }
 // 作用域插槽
 // support single function children as default scoped slot
 if (Array.isArray(children) &&
 typeof children[0] === &#39;function&#39;
 ) {
 data = data || {}
 data.scopedSlots = { default: children[0] }
 children.length = 0
 }
 // 根據(jù)normalizationType的值,選擇不同的處理方法
 if (normalizationType === ALWAYS_NORMALIZE) {
 children = normalizeChildren(children)
 } else if (normalizationType === SIMPLE_NORMALIZE) {
 children = simpleNormalizeChildren(children)
 }
 let vnode, ns
 // 如果標(biāo)簽名是字符串類型
 if (typeof tag === &#39;string&#39;) {
 let Ctor
 // 獲取標(biāo)簽的命名空間
 ns = (context.$vnode && context.$vnode.ns) || config.getTagNamespace(tag)
 // 如果是保留標(biāo)簽
 if (config.isReservedTag(tag)) {
  // platform built-in elements
  // 就創(chuàng)建這樣一個(gè)vnode
  vnode = new VNode(
  config.parsePlatformTagName(tag), data, children,
  undefined, undefined, context
  )
  // 如果不是保留字標(biāo)簽,嘗試從vm的components上查找是否有這個(gè)標(biāo)簽的定義
 } else if (isDef(Ctor = resolveAsset(context.$options, &#39;components&#39;, tag))) {
  // component
  // 如果找到,就創(chuàng)建虛擬組件節(jié)點(diǎn)
  vnode = createComponent(Ctor, data, context, children, tag)
 } else {
  // unknown or unlisted namespaced elements
  // check at runtime because it may get assigned a namespace when its
  // parent normalizes children
  // 兜底方案,創(chuàng)建一個(gè)正常的vnode
  vnode = new VNode(
  tag, data, children,
  undefined, undefined, context
  )
 }
 } else {
 // 當(dāng)tag不是字符串的時(shí)候,我們認(rèn)為tag是組件的構(gòu)造類
 // 所以直接創(chuàng)建
 // direct component options / constructor
 vnode = createComponent(tag, data, context, children)
 }
 if (isDef(vnode)) {
 // 應(yīng)用命名空間
 if (ns) applyNS(vnode, ns)
 return vnode
 } else {
 // 返回一個(gè)空節(jié)點(diǎn)
 return createEmptyVNode()
 }
}
function applyNS (vnode, ns, force) {
 vnode.ns = ns
 if (vnode.tag === &#39;foreignObject&#39;) {
 // use default namespace inside foreignObject
 ns = undefined
 force = true
 }
 if (isDef(vnode.children)) {
 for (let i = 0, l = vnode.children.length; i < l; i++) {
  const child = vnode.children[i]
  if (isDef(child.tag) && (isUndef(child.ns) || isTrue(force))) {
  applyNS(child, ns, force)
  }
 }
 }
}

4. Principe du patch

La fonction patch est définie dans src/core/vdom/. patch.js. La logique du patch est relativement simple et le code n'est pas collant

La fonction patch re?oit 6 paramètres?:

  • oldVnode?: ancien n?ud virtuel ou ancien n?ud dom réel

  • vnode : nouveau n?ud virtuel

  • hydratant : s'il faut le mélanger avec du vrai dom

  • removeOnly?: drapeau spécial, utilisé pour

  • parentElm?: N?ud parent

  • refElm?: Le nouveau n?ud sera inséré avant refElm

La logique du patch est?:

Si vnode n'existe pas mais que oldVnode existe, cela signifie que l'intention est de détruire l'ancien n?ud, puis appelez InvokeDestroyHook(oldVnode) pour le détruire

Si oldVnode n'existe pas mais que vnode existe, cela signifie que l'intention est de créer un nouveau n?ud, puis appelez createElm pour créer un nouveau n?ud

sinon Lorsque vnode et oldVnode existent

Si oldVnode et vnode sont le même n?ud, appelez patchVnode pour patch

Lorsque vnode et oldVnode ne sont pas le même n?ud, si oldVnode est un Le n?ud dom réel ou hydratant est défini sur true, vous devez utiliser la fonction hydrate pour mapper le dom virtuel et le dom réel, puis définir oldVnode sur le dom virtuel correspondant et trouver le n?ud parent oldVnode.elm, créer un n?ud dom réel basé sur sur vnode et insérez-le dans le n?ud parent à la position de oldVnode.elm

La logique de patchVnode est?:

1 Si oldVnode suit Les vnodes sont complètement cohérents. , vous n'avez donc rien à faire

2. Si oldVnode et vnode sont tous deux des n?uds statiques et ont la même clé, lorsque vnode est un n?ud clone ou un n?ud contr?lé par la commande v-once, uniquement Vous devez copier à la fois oldVnode.elm et oldVnode.child dans vnode, et aucune autre opération n'est requise

3 Sinon, si vnode n'est pas un n?ud de texte ou un n?ud d'annotation

    .
  • Si oldVnode et vnode ont tous deux des n?uds enfants et que les n?uds enfants des deux parties ne sont pas complètement cohérents, exécutez updateChildren

  • Si seul oldVnode a des n?uds enfants, supprimez ces n?uds

  • Si seulement vnode a des n?uds enfants, alors créez ces n?uds enfants

  • Si ni oldVnode ni vnode n'ont de n?uds enfants, mais que oldVnode est un texte node Ou n?ud de commentaire, définissez le texte de vnode.elm sur la cha?ne vide

4.如果vnode是文本節(jié)點(diǎn)或注釋節(jié)點(diǎn),但是vnode.text != oldVnode.text時(shí),只需要更新vnode.elm的文本內(nèi)容就可以

代碼如下:

 function patchVnode (oldVnode, vnode, insertedVnodeQueue, removeOnly) {
 // 如果新舊節(jié)點(diǎn)一致,什么都不做
 if (oldVnode === vnode) {
  return
 }
 // 讓vnode.el引用到現(xiàn)在的真實(shí)dom,當(dāng)el修改時(shí),vnode.el會(huì)同步變化
 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
 }
 // reuse element for static trees.
 // note we only do this if the vnode is cloned -
 // if the new node is not cloned it means the render functions have been
 // reset by the hot-reload-api and we need to do a proper re-render.
 // 如果新舊都是靜態(tài)節(jié)點(diǎn),并且具有相同的key
 // 當(dāng)vnode是克隆節(jié)點(diǎn)或是v-once指令控制的節(jié)點(diǎn)時(shí),只需要把oldVnode.elm和oldVnode.child都復(fù)制到vnode上
 // 也不用再有其他操作
 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)
 }
 // 如果vnode不是文本節(jié)點(diǎn)或者注釋節(jié)點(diǎn)
 if (isUndef(vnode.text)) {
  // 并且都有子節(jié)點(diǎn)
  if (isDef(oldCh) && isDef(ch)) {
  // 并且子節(jié)點(diǎn)不完全一致,則調(diào)用updateChildren
  if (oldCh !== ch) updateChildren(elm, oldCh, ch, insertedVnodeQueue, removeOnly)
  // 如果只有新的vnode有子節(jié)點(diǎn)
  } else if (isDef(ch)) {
  if (isDef(oldVnode.text)) nodeOps.setTextContent(elm, &#39;&#39;)
  // elm已經(jīng)引用了老的dom節(jié)點(diǎn),在老的dom節(jié)點(diǎn)上添加子節(jié)點(diǎn)
  addVnodes(elm, null, ch, 0, ch.length - 1, insertedVnodeQueue)
  // 如果新vnode沒(méi)有子節(jié)點(diǎn),而vnode有子節(jié)點(diǎn),直接刪除老的oldCh
  } else if (isDef(oldCh)) {
  removeVnodes(elm, oldCh, 0, oldCh.length - 1)
  // 如果老節(jié)點(diǎn)是文本節(jié)點(diǎn)
  } else if (isDef(oldVnode.text)) {
  nodeOps.setTextContent(elm, &#39;&#39;)
  }
  // 如果新vnode和老vnode是文本節(jié)點(diǎn)或注釋節(jié)點(diǎn)
  // 但是vnode.text != oldVnode.text時(shí),只需要更新vnode.elm的文本內(nèi)容就可以
 } 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)
 }
 }

5.updataChildren原理

updateChildren的邏輯是:

分別獲取oldVnode和vnode的firstChild、lastChild,賦值給oldStartVnode、oldEndVnode、newStartVnode、newEndVnode

如果oldStartVnode和newStartVnode是同一節(jié)點(diǎn),調(diào)用patchVnode進(jìn)行patch,然后將oldStartVnode和newStartVnode都設(shè)置為下一個(gè)子節(jié)點(diǎn),

如果oldEndVnode和newEndVnode是同一節(jié)點(diǎn),調(diào)用patchVnode進(jìn)行patch,然后將oldEndVnode和newEndVnode都設(shè)置為上一個(gè)子節(jié)點(diǎn),重復(fù)上述流程

如果oldStartVnode和newEndVnode是同一節(jié)點(diǎn),調(diào)用patchVnode進(jìn)行patch,如果removeOnly是false,那么可以把oldStartVnode.elm移動(dòng)到oldEndVnode.elm之后,然后把oldStartVnode設(shè)置為下一個(gè)節(jié)點(diǎn),newEndVnode設(shè)置為上一個(gè)節(jié)點(diǎn),重復(fù)上述流程

如果newStartVnode和oldEndVnode是同一節(jié)點(diǎn),調(diào)用patchVnode進(jìn)行patch,如果removeOnly是false,那么可以把oldEndVnode.elm移動(dòng)到oldStartVnode.elm之前,然后把newStartVnode設(shè)置為下一個(gè)節(jié)點(diǎn),oldEndVnode設(shè)置為上一個(gè)節(jié)點(diǎn),重復(fù)上述流程

如果以上都不匹配,就嘗試在oldChildren中尋找跟newStartVnode具有相同key的節(jié)點(diǎn),如果找不到相同key的節(jié)點(diǎn),說(shuō)明newStartVnode是一個(gè)新節(jié)點(diǎn),就創(chuàng)建一個(gè),然后把newStartVnode設(shè)置為下一個(gè)節(jié)點(diǎn)

如果上一步找到了跟newStartVnode相同key的節(jié)點(diǎn),那么通過(guò)其他屬性的比較來(lái)判斷這2個(gè)節(jié)點(diǎn)是否是同一個(gè)節(jié)點(diǎn),如果是,就調(diào)用patchVnode進(jìn)行patch,如果removeOnly是false,就把newStartVnode.elm插入到oldStartVnode.elm之前,把newStartVnode設(shè)置為下一個(gè)節(jié)點(diǎn),重復(fù)上述流程

如果在oldChildren中沒(méi)有尋找到newStartVnode的同一節(jié)點(diǎn),那就創(chuàng)建一個(gè)新節(jié)點(diǎn),把newStartVnode設(shè)置為下一個(gè)節(jié)點(diǎn),重復(fù)上述流程

如果oldStartVnode跟oldEndVnode重合了,并且newStartVnode跟newEndVnode也重合了,這個(gè)循環(huán)就結(jié)束了

具體代碼如下:

function updateChildren (parentElm, oldCh, newCh, insertedVnodeQueue, removeOnly) {
 let oldStartIdx = 0 // 舊頭索引
 let newStartIdx = 0 // 新頭索引
 let oldEndIdx = oldCh.length - 1 // 舊尾索引
 let newEndIdx = newCh.length - 1 // 新尾索引
 let oldStartVnode = oldCh[0] // oldVnode的第一個(gè)child
 let oldEndVnode = oldCh[oldEndIdx] // oldVnode的最后一個(gè)child
 let newStartVnode = newCh[0] // newVnode的第一個(gè)child
 let newEndVnode = newCh[newEndIdx] // newVnode的最后一個(gè)child
 let oldKeyToIdx, idxInOld, vnodeToMove, refElm
 // removeOnly is a special flag used only by <transition-group>
 // to ensure removed elements stay in correct relative positions
 // during leaving transitions
 const canMove = !removeOnly
 // 如果oldStartVnode和oldEndVnode重合,并且新的也都重合了,證明diff完了,循環(huán)結(jié)束
 while (oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx) {
  // 如果oldVnode的第一個(gè)child不存在
  if (isUndef(oldStartVnode)) {
  // oldStart索引右移
  oldStartVnode = oldCh[++oldStartIdx] // Vnode has been moved left
  // 如果oldVnode的最后一個(gè)child不存在
  } else if (isUndef(oldEndVnode)) {
  // oldEnd索引左移
  oldEndVnode = oldCh[--oldEndIdx]
  // oldStartVnode和newStartVnode是同一個(gè)節(jié)點(diǎn)
  } else if (sameVnode(oldStartVnode, newStartVnode)) {
  // patch oldStartVnode和newStartVnode, 索引左移,繼續(xù)循環(huán)
  patchVnode(oldStartVnode, newStartVnode, insertedVnodeQueue)
  oldStartVnode = oldCh[++oldStartIdx]
  newStartVnode = newCh[++newStartIdx]
  // oldEndVnode和newEndVnode是同一個(gè)節(jié)點(diǎn)
  } else if (sameVnode(oldEndVnode, newEndVnode)) {
  // patch oldEndVnode和newEndVnode,索引右移,繼續(xù)循環(huán)
  patchVnode(oldEndVnode, newEndVnode, insertedVnodeQueue)
  oldEndVnode = oldCh[--oldEndIdx]
  newEndVnode = newCh[--newEndIdx]
  // oldStartVnode和newEndVnode是同一個(gè)節(jié)點(diǎn)
  } else if (sameVnode(oldStartVnode, newEndVnode)) { // Vnode moved right
  // patch oldStartVnode和newEndVnode
  patchVnode(oldStartVnode, newEndVnode, insertedVnodeQueue)
  // 如果removeOnly是false,則將oldStartVnode.eml移動(dòng)到oldEndVnode.elm之后
  canMove && nodeOps.insertBefore(parentElm, oldStartVnode.elm, nodeOps.nextSibling(oldEndVnode.elm))
  // oldStart索引右移,newEnd索引左移
  oldStartVnode = oldCh[++oldStartIdx]
  newEndVnode = newCh[--newEndIdx]
  // 如果oldEndVnode和newStartVnode是同一個(gè)節(jié)點(diǎn)
  } else if (sameVnode(oldEndVnode, newStartVnode)) { // Vnode moved left
  // patch oldEndVnode和newStartVnode
  patchVnode(oldEndVnode, newStartVnode, insertedVnodeQueue)
  // 如果removeOnly是false,則將oldEndVnode.elm移動(dòng)到oldStartVnode.elm之前
  canMove && nodeOps.insertBefore(parentElm, oldEndVnode.elm, oldStartVnode.elm)
  // oldEnd索引左移,newStart索引右移
  oldEndVnode = oldCh[--oldEndIdx]
  newStartVnode = newCh[++newStartIdx]
  // 如果都不匹配
  } else {
  if (isUndef(oldKeyToIdx)) oldKeyToIdx = createKeyToOldIdx(oldCh, oldStartIdx, oldEndIdx)
  // 嘗試在oldChildren中尋找和newStartVnode的具有相同的key的Vnode
  idxInOld = isDef(newStartVnode.key)
   ? oldKeyToIdx[newStartVnode.key]
   : findIdxInOld(newStartVnode, oldCh, oldStartIdx, oldEndIdx)
  // 如果未找到,說(shuō)明newStartVnode是一個(gè)新的節(jié)點(diǎn)
  if (isUndef(idxInOld)) { // New element
   // 創(chuàng)建一個(gè)新Vnode
   createElm(newStartVnode, insertedVnodeQueue, parentElm, oldStartVnode.elm)
  // 如果找到了和newStartVnodej具有相同的key的Vnode,叫vnodeToMove
  } else {
   vnodeToMove = oldCh[idxInOld]
   /* istanbul ignore if */
   if (process.env.NODE_ENV !== &#39;production&#39; && !vnodeToMove) {
   warn(
    &#39;It seems there are duplicate keys that is causing an update error. &#39; +
    &#39;Make sure each v-for item has a unique key.&#39;
   )
   }
   // 比較兩個(gè)具有相同的key的新節(jié)點(diǎn)是否是同一個(gè)節(jié)點(diǎn)
   //不設(shè)key,newCh和oldCh只會(huì)進(jìn)行頭尾兩端的相互比較,設(shè)key后,除了頭尾兩端的比較外,還會(huì)從用key生成的對(duì)象oldKeyToIdx中查找匹配的節(jié)點(diǎn),所以為節(jié)點(diǎn)設(shè)置key可以更高效的利用dom。
   if (sameVnode(vnodeToMove, newStartVnode)) {
   // patch vnodeToMove和newStartVnode
   patchVnode(vnodeToMove, newStartVnode, insertedVnodeQueue)
   // 清除
   oldCh[idxInOld] = undefined
   // 如果removeOnly是false,則將找到的和newStartVnodej具有相同的key的Vnode,叫vnodeToMove.elm
   // 移動(dòng)到oldStartVnode.elm之前
   canMove && nodeOps.insertBefore(parentElm, vnodeToMove.elm, oldStartVnode.elm)
   // 如果key相同,但是節(jié)點(diǎn)不相同,則創(chuàng)建一個(gè)新的節(jié)點(diǎn)
   } else {
   // same key but different element. treat as new element
   createElm(newStartVnode, insertedVnodeQueue, parentElm, oldStartVnode.elm)
   }
  }
  // 右移
  newStartVnode = newCh[++newStartIdx]
  }
 }

6.具體的Diff分析

不設(shè)key,newCh和oldCh只會(huì)進(jìn)行頭尾兩端的相互比較,設(shè)key后,除了頭尾兩端的比較外,還會(huì)從用key生成的對(duì)象oldKeyToIdx中查找匹配的節(jié)點(diǎn),所以為節(jié)點(diǎn)設(shè)置key可以更高效的利用dom。

diff的遍歷過(guò)程中,只要是對(duì)dom進(jìn)行的操作都調(diào)用api.insertBefore,api.insertBefore只是原生insertBefore的簡(jiǎn)單封裝。

比較分為兩種,一種是有vnode.key的,一種是沒(méi)有的。但這兩種比較對(duì)真實(shí)dom的操作是一致的。

對(duì)于與sameVnode(oldStartVnode, newStartVnode)和sameVnode(oldEndVnode,newEndVnode)為true的情況,不需要對(duì)dom進(jìn)行移動(dòng)。

總結(jié)遍歷過(guò)程,有3種dom操作:上述圖中都有

1.當(dāng)oldStartVnode,newEndVnode值得比較,說(shuō)明oldStartVnode.el跑到oldEndVnode.el的后邊了。

2.當(dāng)oldEndVnode,newStartVnode值得比較,oldEndVnode.el跑到了oldStartVnode.el的前邊,準(zhǔn)確的說(shuō)應(yīng)該是oldEndVnode.el需要移動(dòng)到oldStartVnode.el的前邊”。

3.newCh中的節(jié)點(diǎn)oldCh里沒(méi)有, 將新節(jié)點(diǎn)插入到oldStartVnode.el的前邊

在結(jié)束時(shí),分為兩種情況:

1.oldStartIdx > oldEndIdx,可以認(rèn)為oldCh先遍歷完。當(dāng)然也有可能newCh此時(shí)也正好完成了遍歷,統(tǒng)一都?xì)w為此類。此時(shí)newStartIdx和newEndIdx之間的vnode是新增的,調(diào)用addVnodes,把他們?nèi)坎暹M(jìn)before的后邊,before很多時(shí)候是為null的。addVnodes調(diào)用的是insertBefore操作dom節(jié)點(diǎn),我們看看insertBefore的文檔:parentElement.insertBefore(newElement, referenceElement)

如果referenceElement為null則newElement將被插入到子節(jié)點(diǎn)的末尾。如果newElement已經(jīng)在DOM樹(shù)中,newElement首先會(huì)從DOM樹(shù)中移除。所以before為null,newElement將被插入到子節(jié)點(diǎn)的末尾。

2.newStartIdx > newEndIdx, on peut considérer que newCh est parcouru en premier. Pour le moment, le vnode entre oldStartIdx et oldEndIdx n'existe plus dans le nouveau n?ud enfant. Appelez RemoveVnodes pour les supprimer du dom

Ce qui précède est ce que j'ai compilé pour tout le monde. J'espère que cela sera utile à tout le monde. à l'avenir.

Articles associés?:

Chrome Firefox est livré avec des outils de débogage (tutoriel détaillé)

à propos de la fa?on dont Vue.js implémente le chargement par défilement infini

Comment implémenter le filtrage de tableaux à l'aide d'Angular

Comment implémenter une calculatrice à l'aide de JavaScript

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefa?on, veuillez contacter admin@php.cn

Outils d'IA chauds

Undress AI Tool

Undress AI Tool

Images de déshabillage gratuites

Undresser.AI Undress

Undresser.AI Undress

Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover

AI Clothes Remover

Outil d'IA en ligne pour supprimer les vêtements des photos.

Clothoff.io

Clothoff.io

Dissolvant de vêtements AI

Video Face Swap

Video Face Swap

échangez les visages dans n'importe quelle vidéo sans effort grace à notre outil d'échange de visage AI entièrement gratuit?!

Article chaud

Outils chauds

Bloc-notes++7.3.1

Bloc-notes++7.3.1

éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise

SublimeText3 version chinoise

Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1

Envoyer Studio 13.0.1

Puissant environnement de développement intégré PHP

Dreamweaver CS6

Dreamweaver CS6

Outils de développement Web visuel

SublimeText3 version Mac

SublimeText3 version Mac

Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Sujets chauds

Tutoriel PHP
1502
276
Quelle est la signification de la transformation de la réactivité de Vue (expérimentale, puis supprimée) et de ses objectifs? Quelle est la signification de la transformation de la réactivité de Vue (expérimentale, puis supprimée) et de ses objectifs? Jun 20, 2025 am 01:01 AM

ReactivitytransforminVue3aimedtosimplifyhandlingreactivedatabyautomaticallytrackingandmanagingreactivitywithoutrequiringmanualref()or.valueusage.Itsoughttoreduceboilerplateandimprovecodereadabilitybytreatingvariableslikeletandconstasautomaticallyreac

Que sont les algorithmes à Python, et pourquoi sont-ils importants? Que sont les algorithmes à Python, et pourquoi sont-ils importants? Jun 24, 2025 am 12:43 AM

AlgorithmsInpyThonareEssentialForFicientProblem-SolvingInProgramming.

Comment l'internationalisation (I18N) et la localisation (L10N) peuvent-elles être mises en ?uvre dans une application VUE? Comment l'internationalisation (I18N) et la localisation (L10N) peuvent-elles être mises en ?uvre dans une application VUE? Jun 20, 2025 am 01:00 AM

Internationalisation et olocalisation dans la variation des acquis

Qu'est-ce que le c?té serveur Rendre SSR dans Vue? Qu'est-ce que le c?té serveur Rendre SSR dans Vue? Jun 25, 2025 am 12:49 AM

Server-sideredering (SSR) invueImproveSperformanceAndSeoBygeneratingHtmlONTheServer.1.TheServerrunsvueAppcodeandGenerateshtmlBaseDonthecurrentRoute.2.ThathtmLissentToHebroweToWeTerterActive.

Comment construire une bibliothèque de composants avec Vue? Comment construire une bibliothèque de composants avec Vue? Jul 10, 2025 pm 12:14 PM

La construction d'une bibliothèque de composants Vue nécessite la conception de la structure autour du scénario d'entreprise et le suivi du processus complet de développement, de test et de libération. 1. La conception structurelle doit être classée en fonction des modules fonctionnels, y compris des composants de base, des composants de mise en page et des composants commerciaux; 2. Utilisez des variables SCSS ou CSS pour unifier le thème et le style; 3. Unifier les spécifications de dénomination et introduire Eslint et plus joli pour assurer le style de code cohérent; 4. Afficher l'utilisation des composants sur le site de document de support; 5. Utilisez VITE et d'autres outils pour emballer en tant que packages NPM et configurer les rolupoptions; 6. Suivez la spécification SEMVER pour gérer les versions et les modifications modifiées lors de la publication.

Comment implémenter les transitions et les animations dans Vue? Comment implémenter les transitions et les animations dans Vue? Jun 24, 2025 pm 02:17 PM

ToaddtransitionsandanimationsInvue, usebuilt-incomponentslikeandand, applatcsclasses, leveragetransitionhooksforControl, andoptimezeperformance.1.wrapelementswithandapplycsstransitionclasses lisev-enter-actinterforbasicfadeorslideeffets.2.

Quel est le but de la fonction NextTick à Vue, et quand est-elle nécessaire? Quel est le but de la fonction NextTick à Vue, et quand est-elle nécessaire? Jun 19, 2025 am 12:58 AM

NextTick est utilisé dans Vue pour exécuter du code après la mise à jour DOM. Lorsque les données changent, Vue ne mettra pas à jour le DOM immédiatement, mais le mettra dans la file d'attente et le traitera dans la prochaine boucle d'événement "Tick". Par conséquent, si vous devez accéder ou exploiter le DOM mis à jour, NextTick doit être utilisé; Les scénarios courants incluent: l'accès au contenu DOM mis à jour, la collaboration avec des bibliothèques tierces qui s'appuient sur l'état DOM et le calcul en fonction de la taille de l'élément; Son utilisation comprend l'appel. $ NextTick comme méthode de composant, l'utiliser seul après l'importation et la combinaison asynchrone / attendre; Les précautions comprennent: éviter une utilisation excessive, dans la plupart des cas, aucun déclenchement manuel n'est requis, et un prochain peut capturer plusieurs mises à jour à la fois.

Comment utiliser PHP pour développer une plate-forme communautaire Q&A explication détaillée du modèle de monétisation communautaire interactive PHP Comment utiliser PHP pour développer une plate-forme communautaire Q&A explication détaillée du modèle de monétisation communautaire interactive PHP Jul 23, 2025 pm 07:21 PM

1. Le premier choix pour la combinaison Laravel Mysql Vue / React dans la communauté de questions et réponses de développement PHP est le premier choix pour la combinaison Laravel Mysql Vue / React, en raison de sa maturité dans l'écosystème et de l'efficacité de développement élevée; 2. Les performances élevées nécessitent une dépendance à la cache (redis), une optimisation de la base de données, des files d'attente CDN et asynchrones; 3. La sécurité doit être effectuée avec le filtrage d'entrée, la protection CSRF, les HTTP, le cryptage de mot de passe et le contr?le d'autorisation; 4. Publicité facultative, abonnement aux membres, récompenses, commissions, paiement des connaissances et autres modèles, le noyau est de faire correspondre le ton communautaire et les besoins des utilisateurs.

See all articles