Vue使用虛擬dom進行渲染view的方法
前提
vue版本:v2.5.17-beta.0
觸發(fā)render
vue在數據更新后會自動觸發(fā)view的render工作,其依賴于數據驅動;在數據驅動的工作下,每一個vue的data屬性都被監(jiān)聽,并且在set觸發(fā)時,派發(fā)事件,通知收集到的依賴,從而觸發(fā)對應的操作,render工作就是其中的一個依賴,并且被每一個data屬性所收集,因此每一個data屬性改變后,都會觸發(fā)render。
vue更新監(jiān)聽
看一段代碼
// 來自mountComponent函數 updateComponent = function () { vm._update(vm._render(), hydrating); }; new Watcher(vm, updateComponent, noop, { before: function before () { if (vm._isMounted) { callHook(vm, 'beforeUpdate'); } } }, true /* isRenderWatcher */);
updateComponent是更新組件的函數,內部調用vm._update,并且傳參vm._render();
- vm._render()返回了什么?看源碼則得知返回了虛擬dom(VNode)
- vm._update函數又做了什么事情?顧名思義,更新傳入的vnode
- 什么時候觸發(fā)updateComponent函數?在任何vue的data屬性更改值都會觸發(fā)
更新view
閱讀_update函數得知,最終調用了vm.__patch__方法,最終找到為createPatchFunction方法的返回值
var patch = createPatchFunction({ nodeOps: nodeOps, modules: modules }); Vue.prototype.__patch__ = inBrowser ? patch : noop;
接下來重點看createPatchFunction的返回函數patch.
如果新的vnode不存在,則注銷舊的vnode
if (isUndef(vnode)) { if (isDef(oldVnode)) { invokeDestroyHook(oldVnode); } return }
如果舊的vnode不存在,則創(chuàng)建新的vnode
if (isUndef(oldVnode)) { // empty mount (likely as component), create new root element isInitialPatch = true; createElm(vnode, insertedVnodeQueue); }
如果以上不成立,則新的vnode和oldVnode都存在.如果oldVnode不是真實的dom,則為虛擬dom節(jié)點,并且新老vnode相似,則進行diff算法
var isRealElement = isDef(oldVnode.nodeType); if (!isRealElement && sameVnode(oldVnode, vnode)) { // patch existing root node patchVnode(oldVnode, vnode, insertedVnodeQueue, removeOnly); }
如果新老vnode不同,則拿到oldVnode的父節(jié)點,輔助創(chuàng)建vnode的新節(jié)點
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) );
以上的步驟發(fā)現,更新view時,重點進入到了patchVnode函數,因此下面進入patchVnode的函數閱讀
如果新老node相等,則不做處理
if (oldVnode === vnode) { return }
如果vnode不是文本節(jié)點則有幾種情況
if (isDef(oldCh) && isDef(ch)) { // 如果oldVnode和vnode的children都有值(組件層),并且不想等,則執(zhí)行更新children流程 if (oldCh !== ch) { updateChildren(elm, oldCh, ch, insertedVnodeQueue, removeOnly); } } else if (isDef(ch)) { // 如果vnode的children有值,如果當前dom有文本則清空, // 并將oldVnode的dom作為父節(jié)點,創(chuàng)建新vnode的children節(jié)點 if (isDef(oldVnode.text)) { nodeOps.setTextContent(elm, ''); } addVnodes(elm, null, ch, 0, ch.length - 1, insertedVnodeQueue); } else if (isDef(oldCh)) { // 如果oldVnode存在children,但是新的沒有,則刪除oldVnode的children的vnode removeVnodes(elm, oldCh, 0, oldCh.length - 1); } else if (isDef(oldVnode.text)) { // 如果oldVnode有文本信息,則將dom的文本清空 nodeOps.setTextContent(elm, ''); }
如果vnode是文本節(jié)點, 則當新老節(jié)點文本不同,將dom的文本更新成新vnode的文本
else if (oldVnode.text !== vnode.text) { nodeOps.setTextContent(elm, vnode.text); }
patchVnode函數處理的情況梳理一下則為:
- 如果新老vnode相同,不作處理
- 如果新vnode是文本節(jié)點,并且新老文本不同,將dom更新為vnode的文本
- 如果新老vnode都有children,表示他們是組件層,則調用updateChildren去做組件層更新
- 如果新vnode是組件層,oldVnode不是,則將當前dom添加新vnode組件的子元素
- 如果oldVnode是組件層,新vnode不是,則操作dom,將oldVnode包含的子元素刪除
- 如果新vnode是組件層,oldVnode是文本節(jié)點,則將dom的文本清空
在patchVnode部分又浮現了一個新的函數:updateChildren,是在新老vnode都不是文本節(jié)點時調用的,這里就是vue的渲染機制的核心
updateChildren
updateChildren中將新老vnode的children進行的循環(huán)處理,每一次循環(huán)去判斷是否有相同的vnode,如果沒有則查找當前新vnode的子節(jié)點的key是否存在oldVnode的children中,如果不存在在這存在但已經不相同則創(chuàng)建新的dom,否則,如果是新老節(jié)點相同,回調patchVnode函數去處理2個節(jié)點。 這樣進行了遞歸處理,組件層的更新就完成了。
結尾
本文為看源碼分析vue更新機制部分,省略了特殊場景的源碼分析,比如ssr、靜態(tài)組件等。
總結
以上所述是小編給大家介紹的Vue使用虛擬dom進行渲染view的方法,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對我們網站的支持!
如果你覺得本文對你有幫助,歡迎轉載,煩請注明出處,謝謝!
欄 目:JavaScript
下一篇:vue點擊按鈕動態(tài)創(chuàng)建與刪除組件功能
本文地址:http://mengdiqiu.com.cn/a1/JavaScript/9368.html
您可能感興趣的文章
- 04-02包含javascript舍的詞條
- 01-10使用webpack/gulp構建TypeScript項目的方法示例
- 01-10使用JS來動態(tài)操作css的幾種方法
- 01-10在Vue項目中使用Typescript的實現
- 01-10Vue中使用Lodop插件實現打印功能的簡單方法
- 01-10echarts實現折線圖的拖拽效果
- 01-10JS數據類型STRING使用實例解析
- 01-10node使用request請求的方法
- 01-10angularjs模態(tài)框的使用代碼實例
- 01-10Vue filter 過濾當前時間 實現實時更新效果


閱讀排行
本欄相關
- 04-02javascript點線,點線的代碼
- 04-02javascript潛力,javascript強大嗎
- 04-02javascript替換字符串,js字符串的替換
- 04-02javascript移出,js 移入移出
- 04-02包含javascript舍的詞條
- 04-02javascript并行,深入理解并行編程 豆瓣
- 04-02javascript匿名,js匿名方法
- 04-02javascript警報,JavaScript警告
- 04-02javascript遮蓋,JavaScript遮蓋PC端頁面
- 04-02javascript前身,javascript的前身
隨機閱讀
- 01-10使用C語言求解撲克牌的順子及n個骰子
- 01-10delphi制作wav文件的方法
- 08-05DEDE織夢data目錄下的sessions文件夾有什
- 04-02jquery與jsp,用jquery
- 08-05織夢dedecms什么時候用欄目交叉功能?
- 08-05dedecms(織夢)副欄目數量限制代碼修改
- 01-10SublimeText編譯C開發(fā)環(huán)境設置
- 01-11ajax實現頁面的局部加載
- 01-10C#中split用法實例總結
- 01-11Mac OSX 打開原生自帶讀寫NTFS功能(圖文