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

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

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

1.什么是虛擬DOM

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

2.引入虛擬DOM的目的

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

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

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其實就是一個描述節(jié)點的對象,描述如何創(chuàng)建真實的DOM節(jié)點;vnode的作用就是新舊vnode進行對比,只更新發(fā)生變化的節(jié)點。 VNode有注釋節(jié)點、文本節(jié)點、元素節(jié)點、組件節(jié)點、函數(shù)式組件、克隆節(jié)點:

注釋節(jié)點

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é)點

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

只有一個text屬性

克隆節(jié)點

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

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

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

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

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

(2) componentInstance: 組件的實例,也是Vue的實例 對應(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ù)組件通過createFunctionalComponent函數(shù)創(chuàng)建, 跟組件節(jié)點類似,暫時沒看到特殊屬性,有的話后續(xù)再補上。

patch

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

patch簡介

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

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

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

初次渲染過程

當(dāng)oldvnode中不存在,而vnode中存在時,就需要使用vnode新生成真實的DOM節(jié)點并插入到視圖中。首先如果vnode具有tag屬性,則認(rèn)為它是元素屬性,再根據(jù)當(dāng)前環(huán)境創(chuàng)建真實的元素節(jié)點,元素創(chuàng)建后將它插入到指定的父節(jié)點。以上節(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 */); ,注意第一個參數(shù)是oldVnode為 vm.$el 為元素節(jié)點,__patch__函數(shù)具體過程為:

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

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

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

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

創(chuàng)建一個oldVnode節(jié)點,其形式為

{
 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é)點以及其父節(jié)點,并創(chuàng)建新的節(jié)點

// 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é)點的過程

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

接著在對子節(jié)點處理

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é)點elem,創(chuàng)建子節(jié)點 createChildren(vnode, children, insertedVnodeQueue); 該函數(shù)遍歷子節(jié)點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é)點

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);
}

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

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

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

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é)點
   rm();
  }
 } else {
  removeNode(vnode.elm);
 }
}

初次渲染結(jié)束。

更新節(jié)點過程

為了更好地測試,模板選用

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

點擊按鈕,會更新message,重新渲染視圖,生成的VNode為

{
 asyncFactory: undefined,
 asyncMeta: undefined,
 children: [VNode, VNode],
 componentInstance: undefined,
 componentOptions: undefined,
 context: Vue實例,
 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
}

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

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

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

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

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

if (oldVnode === vnode) {
 return
}

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

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

接著對兩者的屬性值作對比,并更新

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的對比以及相應(yīng)的DOM操作具體如下:

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

對于子節(jié)點的對比,先分別定義oldVnode和vnode兩數(shù)組的前后兩個指針?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;

如下圖:

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

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

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

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

接下來這一塊,是將 oldStartIdx、newStartIdx、oldEndIdx 以及 newEndIdx 兩兩比對的過程,共四種:

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é)點直接移動到oldEndVnode.elm節(jié)點后面,然后將oldStartIdx向后移一位,newEndIdx向前移動一位。 第四種: 后前相等比較

將oldEndVnode.elm節(jié)點直接移動到oldStartVnode.elm節(jié)點后面,然后將oldEndIdx向前移一位,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, 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索引對應(yīng)的map表,如果還是沒有找到節(jié)點,則新創(chuàng)建節(jié)點

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

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

 

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

總結(jié)

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

相關(guān)文章

  • Vue?transition組件簡單實現(xiàn)數(shù)字滾動

    Vue?transition組件簡單實現(xiàn)數(shù)字滾動

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

    詳解Vue項目引入CreateJS的方法(親測可用)

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

    Vue使用三種方法刷新頁面

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

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

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

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

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

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

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

    vue代理模式解決跨域詳解

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

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

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

    Vue中的nextTick方法詳解

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

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

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

最新評論