欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Vue內(nèi)部渲染視圖的方法

 更新時(shí)間:2019年09月02日 10:03:11   作者:小旋風(fēng)我來(lái)了  
這篇文章主要介紹了Vue內(nèi)部渲染視圖的方法,本文通過(guò)實(shí)例代碼圖文并茂的形式給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下

1.什么是虛擬DOM

  •  以前M的命令式操作DOM即使用jQuery操作DOM節(jié)點(diǎn),隨著狀態(tài)的增多,DOM的操作就會(huì)越來(lái)越頻繁,程序的狀態(tài)也越難維護(hù),現(xiàn)在主流的框架都是采用聲明式操作DOM,將操作DOM的方法封裝起來(lái),我們只要更改數(shù)據(jù)的狀態(tài),框架本身會(huì)幫我們操作DOM。
  • 虛擬DOM根據(jù)狀態(tài)建立一顆虛擬節(jié)點(diǎn)樹(shù),新的虛擬節(jié)點(diǎn)樹(shù)會(huì)與舊的虛擬節(jié)點(diǎn)樹(shù)進(jìn)行對(duì)比,只渲染發(fā)生改變的部分,如下圖:

2.引入虛擬DOM的目的

  •  把渲染過(guò)程抽象化,從而使得組件的抽象能力也得到提升,并且可以適配DOM以外的渲染目標(biāo);
  • 可以更好地支持SSR、同構(gòu)渲染等;
  • 不再依賴HTML解析器進(jìn)行模板解析,可以進(jìn)行更多的AOT(預(yù)編譯)工作提高運(yùn)行時(shí)效率,還能將Vue運(yùn)行時(shí)體積進(jìn)一步壓縮。

VNode的定義 Vue中定義了VNode的構(gòu)造函數(shù),這樣我們可以實(shí)例化不同的vnode 實(shí)例如:文本節(jié)點(diǎn)、元素節(jié)點(diǎn)以及注釋節(jié)點(diǎn)等。

var VNode = function VNode (
 tag,
 data,
 children,
 text,
 elm,
 context,
 componentOptions,
 asyncFactory
 ) {
 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;
 };

vnode其實(shí)就是一個(gè)描述節(jié)點(diǎn)的對(duì)象,描述如何創(chuàng)建真實(shí)的DOM節(jié)點(diǎn);vnode的作用就是新舊vnode進(jìn)行對(duì)比,只更新發(fā)生變化的節(jié)點(diǎn)。 VNode有注釋節(jié)點(diǎn)、文本節(jié)點(diǎn)、元素節(jié)點(diǎn)、組件節(jié)點(diǎn)、函數(shù)式組件、克隆節(jié)點(diǎn):

注釋節(jié)點(diǎn)

var createEmptyVNode = function (text) {
 if ( text === void 0 ) text = '';
 var node = new VNode();
 node.text = text;
 node.isComment = true;
 return node
 };

只有isComment和text屬性有效,其余的默認(rèn)為false或者null

文本節(jié)點(diǎn)

function createTextVNode (val) {
 return new VNode(undefined, undefined, undefined, String(val))
 }

只有一個(gè)text屬性

克隆節(jié)點(diǎn)

function cloneVNode (vnode) {
 var cloned = new VNode(
  vnode.tag,
  vnode.data,
  // #7975
  // clone children array to avoid mutating original in case of cloning
  // a child.
  vnode.children && vnode.children.slice(),
  vnode.text,
  vnode.elm,
  vnode.context,
  vnode.componentOptions,
  vnode.asyncFactory
 );
 cloned.ns = vnode.ns;
 cloned.isStatic = vnode.isStatic;
 cloned.key = vnode.key;
 cloned.isComment = vnode.isComment;
 cloned.fnContext = vnode.fnContext;
 cloned.fnOptions = vnode.fnOptions;
 cloned.fnScopeId = vnode.fnScopeId;
 cloned.asyncMeta = vnode.asyncMeta;
 cloned.isCloned = true;
 return cloned
 }

克隆節(jié)點(diǎn)將vnode的所有屬性賦值到clone節(jié)點(diǎn),并且設(shè)置isCloned = true,它的作用是優(yōu)化靜態(tài)節(jié)點(diǎn)和插槽節(jié)點(diǎn)。以靜態(tài)節(jié)點(diǎn)為例,因?yàn)殪o態(tài)節(jié)點(diǎn)的內(nèi)容是不會(huì)改變的,當(dāng)它首次生成虛擬DOM節(jié)點(diǎn)后,再次更新時(shí)是不需要再次生成vnode,而是將原vnode克隆一份進(jìn)行渲染,這樣在一定程度上提升了性能。

元素節(jié)點(diǎn) 元素節(jié)點(diǎn)一般會(huì)存在tag、data、children、context四種有效屬性,形如:

{
 children: [VNode, VNode],
 context: {...},
 tag: 'div',
 data: {attr: {id: app}}
}

組件節(jié)點(diǎn) 組件節(jié)點(diǎn)有兩個(gè)特有屬性 (1) componentOptions,組件節(jié)點(diǎn)的選項(xiàng)參數(shù),包含如下內(nèi)容:

{ Ctor: Ctor, propsData: propsData, listeners: listeners, tag: tag, children: children }

(2) componentInstance: 組件的實(shí)例,也是Vue的實(shí)例 對(duì)應(yīng)的vnode

new VNode(
  ("vue-component-" + (Ctor.cid) + (name ? ("-" + name) : '')),
  data, undefined, undefined, undefined, context,
  { Ctor: Ctor, propsData: propsData, listeners: listeners, tag: tag, children: children },
  asyncFactory
 )

{
 componentOptions: {},
 componentInstance: {},
 tag: 'vue-component-1-child',
 data: {...},
 ...
}

函數(shù)式組件 函數(shù)組件通過(guò)createFunctionalComponent函數(shù)創(chuàng)建, 跟組件節(jié)點(diǎn)類似,暫時(shí)沒(méi)看到特殊屬性,有的話后續(xù)再補(bǔ)上。

patch

虛擬DOM最重要的功能是patch,將VNode渲染為真實(shí)的DOM。

patch簡(jiǎn)介

patch中文意思是打補(bǔ)丁,也就是在原有的基礎(chǔ)上修改DOM節(jié)點(diǎn),也可以說(shuō)是渲染視圖。DOM節(jié)點(diǎn)的修改有三種:

  • 創(chuàng)建新增節(jié)點(diǎn)
  • 刪除廢棄的節(jié)點(diǎn)
  • 修改需要更新的節(jié)點(diǎn)。

當(dāng)緩存上一次的oldvnode與最新的vnode不一致的時(shí)候,渲染視圖以vnode為準(zhǔn)。

初次渲染過(guò)程

當(dāng)oldvnode中不存在,而vnode中存在時(shí),就需要使用vnode新生成真實(shí)的DOM節(jié)點(diǎn)并插入到視圖中。首先如果vnode具有tag屬性,則認(rèn)為它是元素屬性,再根據(jù)當(dāng)前環(huán)境創(chuàng)建真實(shí)的元素節(jié)點(diǎn),元素創(chuàng)建后將它插入到指定的父節(jié)點(diǎn)。以上節(jié)生成的VNode為例,首次執(zhí)行

vm._update(vm._render(), hydrating);

vm._render()為上篇生成的VNode,_update函數(shù)具體為

Vue.prototype._update = function (vnode, hydrating) {
  var vm = this;
  var prevEl = vm.$el;
  var prevVnode = vm._vnode;
  var restoreActiveInstance = setActiveInstance(vm);
  // 緩存vnode
  vm._vnode = vnode;
  // Vue.prototype.__patch__ is injected in entry points
  // based on the rendering backend used.
  // 第一次渲染,preVnode是不存在的
  if (!prevVnode) {
  // initial render
  vm.$el = vm.__patch__(vm.$el, vnode, hydrating, false /* removeOnly */);
  } else {
  // updates
  vm.$el = vm.__patch__(prevVnode, vnode);
  }
  restoreActiveInstance();
  // update __vue__ reference
  if (prevEl) {
  prevEl.__vue__ = null;
  }
  if (vm.$el) {
  vm.$el.__vue__ = vm;
  }
  // if parent is an HOC, update its $el as well
  if (vm.$vnode && vm.$parent && vm.$vnode === vm.$parent._vnode) {
  vm.$parent.$el = vm.$el;
  }
  // updated hook is called by the scheduler to ensure that children are
  // updated in a parent's updated hook.
 };

因第一次渲染,執(zhí)行 vm.$el = vm.__patch__(vm.$el, vnode, hydrating, false /* removeOnly */); ,注意第一個(gè)參數(shù)是oldVnode為 vm.$el 為元素節(jié)點(diǎn),__patch__函數(shù)具體過(guò)程為:

(1) 先判斷oldVnode是否存在,不存在就創(chuàng)建vnode

if (isUndef(oldVnode)) {
 // empty mount (likely as component), create new root element
 isInitialPatch = true;
 createElm(vnode, insertedVnodeQueue);
}

(2) 存在進(jìn)入else,判斷oldVnode是否是元素節(jié)點(diǎn),如果oldVnode是元素節(jié)點(diǎn),則

if (isRealElement) {
 ...
 // either not server-rendered, or hydration failed.
 // create an empty node and replace it
 oldVnode = emptyNodeAt(oldVnode);
}

創(chuàng)建一個(gè)oldVnode節(jié)點(diǎn),其形式為

{
 asyncFactory: undefined,
 asyncMeta: undefined,
 children: [],
 componentInstance: undefined,
 componentOptions: undefined,
 context: undefined,
 data: {},
 elm: div#app,
 fnContext: undefined,
 fnOptions: undefined,
 fnScopeId: undefined,
 isAsyncPlaceholder: false,
 isCloned: false,
 isComment: false,
 isOnce: false,
 isRootInsert: true,
 isStatic: false,
 key: undefined,
 ns: undefined,
 parent: undefined,
 raw: false,
 tag: "div",
 text: undefined,
 child: undefined
}

然后獲取oldVnode的元素節(jié)點(diǎn)以及其父節(jié)點(diǎn),并創(chuàng)建新的節(jié)點(diǎn)

// replacing existing element
var oldElm = oldVnode.elm;
var parentElm = nodeOps.parentNode(oldElm);

// create new node
createElm(
 vnode,
 insertedVnodeQueue,
 // extremely rare edge case: do not insert if old element is in a
 // leaving transition. Only happens when combining transition +
 // keep-alive + HOCs. (#4590)
 oldElm._leaveCb ? null : parentElm,
 nodeOps.nextSibling(oldElm)
);

創(chuàng)建新節(jié)點(diǎn)的過(guò)程

// 標(biāo)記是否是根節(jié)點(diǎn)
 vnode.isRootInsert = !nested; // for transition enter check
 // 這個(gè)函數(shù)如果vnode有componentInstance屬性,會(huì)創(chuàng)建子組件,后續(xù)具體介紹,否則不做處理
if (createComponent(vnode, insertedVnodeQueue, parentElm, refElm)) {
 return
}

接著在對(duì)子節(jié)點(diǎn)處理

var data = vnode.data;
 var children = vnode.children;
 var tag = vnode.tag;
 if (isDef(tag)) {
 ...
 vnode.elm = vnode.ns
  ? nodeOps.createElementNS(vnode.ns, tag)
  : nodeOps.createElement(tag, vnode);
 setScope(vnode);

 /* istanbul ignore if */
 {
  createChildren(vnode, children, insertedVnodeQueue);
  if (isDef(data)) {
   invokeCreateHooks(vnode, insertedVnodeQueue);
  }
  insert(parentElm, vnode.elm, refElm);
 }

 if (data && data.pre) {
  creatingElmInVPre--;
 }
 }
}

將vnode的屬性設(shè)置為創(chuàng)建元素節(jié)點(diǎn)elem,創(chuàng)建子節(jié)點(diǎn) createChildren(vnode, children, insertedVnodeQueue); 該函數(shù)遍歷子節(jié)點(diǎn)children數(shù)組

function createChildren (vnode, children, insertedVnodeQueue) {
 if (Array.isArray(children)) {
  for (var i = 0; i < children.length; ++i) {
   createElm(children[i], insertedVnodeQueue, vnode.elm, null, true, children, i);
  }
 } else if (isPrimitive(vnode.text)) {
  // 如果vnode是文本直接掛載
  nodeOps.appendChild(vnode.elm, nodeOps.createTextNode(String(vnode.text)));
 }
}

遍歷children,遞歸createElm方法創(chuàng)建子元素節(jié)點(diǎn)

else if (isTrue(vnode.isComment)) {
 vnode.elm = nodeOps.createComment(vnode.text);
 insert(parentElm, vnode.elm, refElm);
} else {
 vnode.elm = nodeOps.createTextNode(vnode.text);
 insert(parentElm, vnode.elm, refElm);
}

如果是評(píng)論節(jié)點(diǎn),直接創(chuàng)建評(píng)論節(jié)點(diǎn),并將其插入到父節(jié)點(diǎn)上,其他的創(chuàng)建文本節(jié)點(diǎn),并將其插入到父節(jié)點(diǎn)parentElm(剛創(chuàng)建的div)上去。 觸發(fā)鉤子,更新節(jié)點(diǎn)屬性,將其插入到parentElm('#app'元素節(jié)點(diǎn))上

{
 createChildren(vnode, children, insertedVnodeQueue);
 if (isDef(data)) {
  invokeCreateHooks(vnode, insertedVnodeQueue);
 }
 insert(parentElm, vnode.elm, refElm);
}

最后將老的節(jié)點(diǎn)刪掉

if (isDef(parentElm)) {
 removeVnodes(parentElm, [oldVnode], 0, 0);
} else if (isDef(oldVnode.tag)) {
 invokeDestroyHook(oldVnode);
}
function removeAndInvokeRemoveHook (vnode, rm) {
 if (isDef(rm) || isDef(vnode.data)) {
  var i;
  var listeners = cbs.remove.length + 1;
  ...
  // recursively invoke hooks on child component root node
  if (isDef(i = vnode.componentInstance) && isDef(i = i._vnode) && isDef(i.data)) {
   removeAndInvokeRemoveHook(i, rm);
  }
  for (i = 0; i < cbs.remove.length; ++i) {
   cbs.remove[i](vnode, rm);
  }
  if (isDef(i = vnode.data.hook) && isDef(i = i.remove)) {
   i(vnode, rm);
  } else {
   // 刪除id為app的老節(jié)點(diǎn)
   rm();
  }
 } else {
  removeNode(vnode.elm);
 }
}

初次渲染結(jié)束。

更新節(jié)點(diǎn)過(guò)程

為了更好地測(cè)試,模板選用

<div id="app">{{ message }}<button @click="update">更新</button></div>

點(diǎn)擊按鈕,會(huì)更新message,重新渲染視圖,生成的VNode為

{
 asyncFactory: undefined,
 asyncMeta: undefined,
 children: [VNode, VNode],
 componentInstance: undefined,
 componentOptions: undefined,
 context: Vue實(shí)例,
 data: {attrs: {id: "app"}},
 elm: undefined,
 fnContext: undefined,
 fnOptions: undefined,
 fnScopeId: undefined,
 isAsyncPlaceholder: false,
 isCloned: false,
 isComment: false,
 isOnce: false,
 isRootInsert: true,
 isStatic: false,
 key: undefined,
 ns: undefined,
 parent: undefined,
 raw: false,
 tag: "div",
 text: undefined,
 child: undefined
}

在組件更新的時(shí)候,preVnode和vnode都是存在的,執(zhí)行

vm.$el = vm.__patch__(prevVnode, vnode);

實(shí)際上是運(yùn)行以下函數(shù)

patchVnode(oldVnode, vnode, insertedVnodeQueue, null, null, removeOnly);

該函數(shù)首先判斷oldVnode和vnode是否相等,相等則立即返回

if (oldVnode === vnode) {
 return
}

如果兩者均為靜態(tài)節(jié)點(diǎn)且key值相等,且vnode是被克隆或者具有isOnce屬性時(shí),vnode的組件實(shí)例componentInstance直接賦值

if (isTrue(vnode.isStatic) &&
 isTrue(oldVnode.isStatic) &&
 vnode.key === oldVnode.key &&
 (isTrue(vnode.isCloned) || isTrue(vnode.isOnce))
) {
 vnode.componentInstance = oldVnode.componentInstance;
 return
}

接著對(duì)兩者的屬性值作對(duì)比,并更新

var oldCh = oldVnode.children;
var ch = vnode.children;
if (isDef(data) && isPatchable(vnode)) {
 for (i = 0; i < cbs.update.length; ++i) {  // 以vnode為準(zhǔn)更新oldVnode的不同屬性
  cbs.update[i](oldVnode, vnode); 
 }
 if (isDef(i = data.hook) && isDef(i = i.update)) { 
  i(oldVnode, vnode); 
 }
}

vnode和oldVnode的對(duì)比以及相應(yīng)的DOM操作具體如下:

// vnode不存在text屬性的情況
if (isUndef(vnode.text)) {
 if (isDef(oldCh) && isDef(ch)) {
 // 子節(jié)點(diǎn)不相等時(shí),更新
 if (oldCh !== ch) { 
  updateChildren(elm, oldCh, ch, insertedVnodeQueue, removeOnly); }
 } else if (isDef(ch)) {
  {
  checkDuplicateKeys(ch);
  }
  // 只存在vnode的子節(jié)點(diǎn),如果oldVnode存在text屬性,則將元素的文本內(nèi)容清空,并新增elm節(jié)點(diǎn)
  if (isDef(oldVnode.text)) {    nodeOps.setTextContent(elm, ''); 
  }
  addVnodes(elm, null, ch, 0, ch.length - 1, insertedVnodeQueue);
 } else if (isDef(oldCh)) {
  // 如果只存在oldVnode的子節(jié)點(diǎn),則刪除DOM的子節(jié)點(diǎn)
  removeVnodes(elm, oldCh, 0, oldCh.length - 1);
 } else if (isDef(oldVnode.text)) {
  // 只存在oldVnode有text屬性,將元素的文本清空
  nodeOps.setTextContent(elm, '');
 }
} else if (oldVnode.text !== vnode.text) {
 // node和oldVnode的text屬性都存在且不一致時(shí),元素節(jié)點(diǎn)內(nèi)容設(shè)置為vnode.text
 nodeOps.setTextContent(elm, vnode.text);
}

對(duì)于子節(jié)點(diǎn)的對(duì)比,先分別定義oldVnode和vnode兩數(shù)組的前后兩個(gè)指針?biāo)饕?/p>

var oldStartIdx = 0;
var newStartIdx = 0;
var oldEndIdx = oldCh.length - 1;
var oldStartVnode = oldCh[0];
var oldEndVnode = oldCh[oldEndIdx];
var newEndIdx = newCh.length - 1;
var newStartVnode = newCh[0];
var newEndVnode = newCh[newEndIdx];
var oldKeyToIdx, idxInOld, vnodeToMove, refElm;

如下圖:

接下來(lái)是一個(gè)while循環(huán),在這過(guò)程中,oldStartIdx、newStartIdx、oldEndIdx 以及 newEndIdx 會(huì)逐漸向中間靠攏

while (oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx) 

當(dāng)oldStartVnode或者oldEndVnode為空時(shí),兩中間移動(dòng)

if (isUndef(oldStartVnode)) {
 oldStartVnode = oldCh[++oldStartIdx]; // Vnode has been moved left
} else if (isUndef(oldEndVnode)) {
 oldEndVnode = oldCh[--oldEndIdx];
} 

接下來(lái)這一塊,是將 oldStartIdx、newStartIdx、oldEndIdx 以及 newEndIdx 兩兩比對(duì)的過(guò)程,共四種:

else if (sameVnode(oldStartVnode, newStartVnode)) {
 patchVnode(oldStartVnode, newStartVnode, insertedVnodeQueue, newCh, newStartIdx);
 oldStartVnode = oldCh[++oldStartIdx];
 newStartVnode = newCh[++newStartIdx];
} else if (sameVnode(oldEndVnode, newEndVnode)) {
 patchVnode(oldEndVnode, newEndVnode, insertedVnodeQueue, newCh, newEndIdx);
 oldEndVnode = oldCh[--oldEndIdx];
 newEndVnode = newCh[--newEndIdx];
} else if (sameVnode(oldStartVnode, newEndVnode)) { // Vnode moved right
 patchVnode(oldStartVnode, newEndVnode, insertedVnodeQueue, newCh, newEndIdx);
 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, newCh, newStartIdx);
 canMove && nodeOps.insertBefore(parentElm, oldEndVnode.elm, oldStartVnode.elm);
 oldEndVnode = oldCh[--oldEndIdx];
 newStartVnode = newCh[++newStartIdx];
}

第一種: 前前相等比較

如果相等,則oldStartVnode.elm和newStartVnode.elm均向后移一位,繼續(xù)比較。 第二種: 后后相等比較

如果相等,則oldEndVnode.elmnewEndVnode.elm均向前移一位,繼續(xù)比較。 第三種: 前后相等比較

將oldStartVnode.elm節(jié)點(diǎn)直接移動(dòng)到oldEndVnode.elm節(jié)點(diǎn)后面,然后將oldStartIdx向后移一位,newEndIdx向前移動(dòng)一位。 第四種: 后前相等比較

將oldEndVnode.elm節(jié)點(diǎn)直接移動(dòng)到oldStartVnode.elm節(jié)點(diǎn)后面,然后將oldEndIdx向前移一位,newStartIdx向后移動(dòng)一位。 如果以上均不滿足,則

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, newCh, newStartIdx);
      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];
}

createkeyToOldIdx函數(shù)的作用是建立key和index索引對(duì)應(yīng)的map表,如果還是沒(méi)有找到節(jié)點(diǎn),則新創(chuàng)建節(jié)點(diǎn)

createElm(newStartVnode, insertedVnodeQueue, parentElm, oldStartVnode.elm, false, newCh, newStartIdx);

插入到oldStartVnode.elm節(jié)點(diǎn)前面,否則,如果找到了節(jié)點(diǎn),并符合sameVnode,將兩個(gè)節(jié)點(diǎn)patchVnode,并將該位置的老節(jié)點(diǎn)置為undefined,同時(shí)將vnodeToMove.elm移到oldStartVnode.elm的前面,以及newStartIdx往后移一位,示意圖如下:

 

如果不符合sameVnode,只能創(chuàng)建一個(gè)新節(jié)點(diǎn)插入到 parentElm 的子節(jié)點(diǎn)中,newStartIdx 往后移動(dòng)一位。 最后如果,oldStartIdx > oldEndIdx,說(shuō)明老節(jié)點(diǎn)比對(duì)完了,但是新節(jié)點(diǎn)還有多的,需要將新節(jié)點(diǎn)插入到真實(shí) DOM 中去,調(diào)用 addVnodes 將這些節(jié)點(diǎn)插入即可;如果滿足 newStartIdx > newEndIdx 條件,說(shuō)明新節(jié)點(diǎn)比對(duì)完了,老節(jié)點(diǎn)還有多,將這些無(wú)用的老節(jié)點(diǎn)通過(guò) removeVnodes 批量刪除即可。到這里這個(gè)過(guò)程基本結(jié)束。

總結(jié)

以上所述是小編給大家介紹的Vue內(nèi)部渲染視圖的方法,希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!
如果你覺(jué)得本文對(duì)你有幫助,歡迎轉(zhuǎn)載,煩請(qǐng)注明出處,謝謝!

相關(guān)文章

  • Vue?transition組件簡(jiǎn)單實(shí)現(xiàn)數(shù)字滾動(dòng)

    Vue?transition組件簡(jiǎn)單實(shí)現(xiàn)數(shù)字滾動(dòng)

    這篇文章主要為大家介紹了Vue?transition組件簡(jiǎn)單實(shí)現(xiàn)數(shù)字滾動(dòng)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-09-09
  • 詳解Vue項(xiàng)目引入CreateJS的方法(親測(cè)可用)

    詳解Vue項(xiàng)目引入CreateJS的方法(親測(cè)可用)

    CreateJS是基于HTML5開(kāi)發(fā)的一套模塊化的庫(kù)和工具。這篇文章主要介紹了Vue項(xiàng)目引入CreateJS的方法(親測(cè)),需要的朋友可以參考下
    2019-05-05
  • Vue使用三種方法刷新頁(yè)面

    Vue使用三種方法刷新頁(yè)面

    這篇文章說(shuō)明了如何使用Vue去刷新當(dāng)前頁(yè)面的多種方法實(shí)例,有完成的代碼提供參考,希望對(duì)你有所幫助
    2021-06-06
  • element-ui在table中如何禁用其中幾行

    element-ui在table中如何禁用其中幾行

    這篇文章主要介紹了element-ui在table中如何禁用其中幾行問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-10-10
  • 為什么推薦使用JSX開(kāi)發(fā)Vue3

    為什么推薦使用JSX開(kāi)發(fā)Vue3

    這篇文章主要介紹了為什么推薦使用JSX開(kāi)發(fā)Vue3,幫助大家更好的理解和使用vue框架,感興趣的朋友可以了解下
    2020-12-12
  • 使用yarn?build?打包vue項(xiàng)目時(shí)靜態(tài)文件或圖片未打包成功的問(wèn)題及解決方法

    使用yarn?build?打包vue項(xiàng)目時(shí)靜態(tài)文件或圖片未打包成功的問(wèn)題及解決方法

    這篇文章主要介紹了使用yarn?build?打包vue項(xiàng)目時(shí)靜態(tài)文件或圖片未打包成功的問(wèn)題及解決方法,解決方法不復(fù)雜通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2023-08-08
  • vue代理模式解決跨域詳解

    vue代理模式解決跨域詳解

    這篇文章主要介紹了vue代理模式解決跨域詳解的相關(guān)資料,需要的朋友可以參考下
    2022-09-09
  • 如何解決vue與傳統(tǒng)jquery插件沖突

    如何解決vue與傳統(tǒng)jquery插件沖突

    本篇文章主要介紹了如何解決vue與傳統(tǒng)jquery插件沖突,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-03-03
  • Vue中的nextTick方法詳解

    Vue中的nextTick方法詳解

    Vue的nextTick方法是用來(lái)在下次DOM更新周期中執(zhí)行回調(diào)函數(shù)的方法,用于DOM操作后獲取DOM更新后的狀態(tài),使用場(chǎng)景包括異步更新DOM、獲取更新后元素的位置等情況,一般結(jié)合Vue的異步更新機(jī)制和watch監(jiān)聽(tīng)器使用,實(shí)現(xiàn)方式可使用Promise、setTimeout等異步方法
    2023-04-04
  • 實(shí)例解析Vue.js下載方式及基本概念

    實(shí)例解析Vue.js下載方式及基本概念

    vue是一套用于構(gòu)建用戶界面的漸進(jìn)式框架。接下來(lái)通過(guò)本文給大家分享Vue.js下載方式及基本概念,感興趣的朋友跟隨腳本之家小編一起學(xué)習(xí)吧
    2018-05-05

最新評(píng)論