摘要:閑聊在學的過程中,虛擬應該是聽的最多的概念之一,得知其是借鑒進行開發,故習之。以我的觀點來看,多個相同元素渲染時,則需要為每個元素添加值。
閑聊:在學vue的過程中,虛擬dom應該是聽的最多的概念之一,得知其是借鑒snabbdom.js進行開發,故習之。由于我工作處于IE8的環境,對ES6,TS這些知識的練習也只是淺嘗輒止,而snabbdom.js從v.0.5.4這個版本后開始使用TS,所以我下載了0.5.4這個版本進行學習(后來才發現可以直接下載最新的版本,去dist目錄找編譯好的文件即可,而且這個版本還有BUG,在新版本中得到了修改,建議大家還是下載最新版本進行學習)
總共寫了四篇文章(都是自己的一些拙見,僅供參考,請多多指教,我這邊也會持續修正加更新)
介紹一下snabbdom基本用法
介紹一下snabbdom渲染原理
介紹一下snabddom的diff算法和對key值的認識
介紹一下對于兼容IE8的修改
github
ps:學習的目的是希望將snabbdom.js實踐到工作中去,思前想后,決定拿表格渲染來開刀,而且兼容了IE8
當然我也是站在巨人肩膀上進行學習,參考文章:
snabbdom入門使用
vue2源碼學習開胃菜——snabbdom源碼學習(一)
vue2源碼學習開胃菜——snabbdom源碼學習(二)
好了,前面說了那么多‘廢話’,現在切入主題。
開門見山,先總結一下,通過自己的實踐,個人認為虛擬dom的實現思路為:
通過js對象模擬出一個我們需要渲染到頁面上的dom樹的結構,實現了一個修改js對象即可修改頁面dom的快捷途徑,避免了我們手動再去一次次操作dom-api的繁瑣,而且其提供了算法可以使得用最少的dom操作進行修改。
對于基礎用法的介紹,英語好的完全可以去看一下它github的內容 snabbdom.js,我這邊主要是記錄自己在實踐過程中的一些筆記及踩坑。
1.如何引用我這邊還是以0.5.4版本進行講解
核心文件是:
snabbdom.js
h.js
vnode.js(最新版本改為tovnode.js)
htmldomapi.js
is.js(這個文件是用來提供函數來判斷數據是否為undefined,最新版本已經沒把它多帶帶拿出來了)
polyfill.js(我這邊為了兼容IE8自己添加的文件)
有了這幾個文件其實就可以使用snabbdom.js來渲染我們的頁面。
當然還有很重要的模塊文件:
style.js
props.js
eventlistener.js
class.js
attribute.js
dataset.js
eventlistener.js
這些模塊規定了我們虛擬dom具備哪些能力,例如很重要的eventlistener.js使得我們可以在虛擬dom上添加事件,它們都是我們不可或缺的。作者將其分離出來應該是想剝離出核心代碼,使得我們可以根據自己的需求來定制相應的模塊。
引用的時候各個文件之間還是有一定順序的,我是這樣引用的:(snabbdom.js是最后引用,輔助型文件polyfill.js is.js得最早引用):
當然你也可以把所有文件進行壓縮合并,代碼中還可以使用模塊化的方式進行引用相關模塊;
ps:由于我們這邊還沒有使用模塊化,所以我把源碼中使用模塊化的部分簡單的修改了一下;
模塊化也就是將一個功能多帶帶寫在一個js文件中供其它文件使用,會使用一個對象進行封裝導出,并通過立即執行函數的閉包使得其不會污染其它作用域變量。
舉例:
導出
//a.js
aModule={}; (function(aModule){ aModule.init=function(){} })(aModule)
導入
var init=aModule.init;2.如何使用
先從最簡單的例子來看看snabbdom.js是如何使用的;
代碼如下:
var snabbdom = SnabbdomModule; var patch = snabbdom.init([ //導入相應的模塊 DatasetModule, ClassModule, AttributesModule, PropsModule, StyleModule, EventlistenerModule ]); var h = HModule.h; var app = document.getElementById("app"); var newVnode = h("div#divId.red", {}, [h("p", {},"已改變")]) var vnode = h("div#divId.red", {}, [h("p",{},"2S后改變")]) vnode = patch(app, vnode); setTimeout(function() { vnode=patch(vnode, newVnode); }, 2000)
上面代碼的主要功能就是渲染,通過snabbdom模塊的init方法返回的patch函數實現,細分的話可以分為初始化渲染和對比渲染;
第一次是初始化的時候,vnode=patch(app,vnode),app作為一個被替換的真實dom傳入,返回一個當前頁面的vnode,作為下一次渲染的對比虛擬dom。(這里需要注意的是,app是在這里作為一個替換dom,渲染后app將會被替換);
第二次是對比渲染,vnode=patch(vnode, newVnode);
上面的h函數是一個重點,它里面的內容其實就是頁面dom元素的一個抽象:
h("div#divId.red", {}, [h("p",{},"2S后改變")]) //通過從上面的這個例子,我們知道如何用snabbdom.js來渲染頁面了,不過漏了一個重點,就是h函數的第二個參數,模塊參數的使用,下面我們改造一下vnode;
vnode = h("div#divId.red", { "class": { "active": true }, "style": { "background": "#fff" }, "on": { "click": clickFn }, "dataset": { "name": "liuzj" }, "hook": { "init": function() { console.log("init") }, "create": function() { console.log("create") }, "insert": function() { console.log("insert") }, "prepatch": function() { console.log("beforePatch") }, "update": function() { console.log("update") }, "postpatch": function() { console.log("postPatch") }, "destroy": function() { console.log("destroy") }, "remove": function(ch, rm) { console.log("remove") rm(); } } }, [h("p", {}, "2S后改變")]) function clickFn() { console.log("click") } vnode = patch(app, vnode);下面是代碼的效果:
class:這里我們可以理解為動態的類名,sel上的類可以理解為靜態的,例如上面class:{active:true}我們可以通過控制這個變量來表示此元素是否是當前被點擊
style:內聯樣式
on:綁定的事件類型
對于綁定事件的實踐:
綁定click事件,不傳自定義參數
var newVnode = h("div", { on: { "click":clickfn1 }},"div") function clickfn1(e,vnode) { console.log(e) console.log(vnode) }
綁定click事件,傳自定義參數
var newVnode = h("div", { on: { "click":[clickfn1,"arg1","arg2"] }},"div") function clickfn1(val1,val2,e,vnode) { console.log(val1) console.log(val2) console.log(e) console.log(vnode) }
為click事件綁定多個回調函數
var newVnode = h("div", { on: { "click":[[clickfn1,"arg1","arg2"],[clickfn2,"arg1","arg2"]] }},"div") function clickfn1(val1,val2,e,vnode) { console.log(val1) console.log(val2) console.log(e) console.log(vnode) } function clickfn2(val1,val2,e,vnode) { console.log(val1) console.log(val2) console.log(e) console.log(vnode) }在綁定多個回調函數時,源碼存在一個問題,回調參數中的event和vnode獲取不到,修改源碼即可:
eventlistener.js:
for (var i = 0; i < handler.length; i++) { invokeHandler(handler[i]); } 改為: for (var i = 0; i < handler.length; i++) { invokeHandler(handler[i], vnode, event); }dataset:data屬性
hook:鉤子函數
這些鉤子函數是在模塊中使用的: pre, create, update, destroy, remove, post.
這些鉤子函數是自己定義在虛擬dom中使用的: init, create, insert, prepatch, update, postpatch, destroy, remove.
在實踐鉤子函數的時候遇到的一些情況:如果你的vnode進行patch的時候sel值不同時,只會觸發init create destroy remove insert ,因為這理會將舊的vnode全部刪創建新的vnode 比如:sel:div --> sel:p
如果你的vnode進行patch的時候sel值相同時,只會觸發beforePatch update postPatch,因為這里只是在舊的vnode上進行更新
在使用remove鉤子函數的時候需要注意的是,函數會返回一個rm函數參數,我們需要執行這個函數才能將刪除舊節點。
舉例說明:
var newVnode = h("div#divId", [h("p", "已改變")]) var vnode = h("div#divId.red", { "hook": { "remove": function() { console.log("remove") } } }, [h("p", "2S后改變")]) vnode = patch(app, vnode); setTimeout(function() { patch(vnode, newVnode); }, 2000)正確使用的方法為:
"remove": function(ch, rm) { console.log("remove") rm(); }
props/attribute:設置元素自身的屬性
h("div#divId.red", [h("a",{ attrs:{ href:"http://baidu.com"}},"百度")]) h("div#divId.red", [h("a",{ props:{ href:"http://baidu.com"}},"百度")])不過對于disabled checked這樣的屬性最好是用props
h("div#divId.red", [h("button", {props: {disabled: true}}, "按鈕")])3.對于Key值的使用key值算是一個snabbdom中diff算法的一個核心內容,關于diff算法的核心思想我會在下一篇介紹,這一篇主要是講一下使用。
以我的觀點來看,多個相同元素渲染時,則需要為每個元素添加key值。
例如
- li1
- li2
- li2
-->- li3
- li3
- li4
var vnode = h("ul", [h("li", { key: 1 }, "li1"), h("li", { key: 2 }, "li2"), h("li", { key: 3 }, "li3")]) var newVnode = h("ul", [h("li", { key: 2 }, "li2"), h("li", { key: 3 }, "li3"), h("li", { key: 4 }, "li4")])當然,在實際工作中,我們肯定不會像上面那樣寫,都是利用循環進行動態渲染。
var data1 = [{ name: "li1" }, { name: "li2" }, { name: "li3" }] var data2 = [{ name: "li2" }, { name: "li3" }, { name: "li4" }] var vnode = h("ul", data1.map(function(item) { return h("li", { key: item.name }, item.name) })) var newVnode = h("ul", data2.map(function(item) { return h("li", { key: item.name }, item.name) })) vnode = patch(app, vnode); setTimeout(function() { patch(vnode, newVnode); }, 2000)這里需要記住的是:這個key值要唯一,而且需要一一對應
很多人喜歡在循環的數組中用index來作為key值,嚴格意義上來說這樣做是不恰當的,key值不僅需要唯一,還需要一一對應(同一個節點舊vnode中和新vnode中的key值要一樣),當然如果你使用key值的元素它不存在增刪和排序的需求,那么index作為key值沒有影響。
至于原因,下一篇我會說一下;前面說到了ul/li需要使用key,還有就是我目前做的表格渲染,也需要使用key,因為表格會涉及到tbody/tr/td,其中tr和td都會存在多個,而tr會有增刪和排序,td只是值的修改,位置不會發生變化,所以我在實際操作的過程中,tr的key值一一對應的,而td的key值則是用index來賦值。
希望大家看完能有收獲,歡迎指正!
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/100343.html
摘要:毫無疑問的是算法的復雜度與效率是決定能夠帶來性能提升效果的關鍵因素。速度略有損失,但可讀性大大提高。因此目前的主流算法趨向一致,在主要思路上,與的方式基本相同。在里面實現了的算法與支持。是唯一添加的方法所以只發生在中。 VirtualDOM是react在組件化開發場景下,針對DOM重排重繪性能瓶頸作出的重要優化方案,而他最具價值的核心功能是如何識別并保存新舊節點數據結構之間差異的方法,...
摘要:這個大概是的鉤子吧在每一次插入操作的時候都將節點這類型方法可以看出來是在調用對應的方法因為開始的時候就導入進來了插入節點操作的時候都需要加入子節點有子元素也就是的時候遞歸調用循環子節點生成對應著一些操作之后都要觸發鉤子函數。 snabbdom 本文的snabbdom源碼分析采用的是0.54版本(即未用ts重寫前的最后一版) 前期了解 snabbdom被用作vue的虛擬dom。本文的一個...
摘要:總共寫了四篇文章都是自己的一些拙見,僅供參考,請多多指教,我這邊也會持續修正加更新介紹一下基本用法介紹一下渲染原理介紹一下的算法和對值的認識介紹一下對于兼容的修改這篇主要是說一下的算法在上一篇中我總結過對比渲染的流程大體分為通過來判斷兩個是 總共寫了四篇文章(都是自己的一些拙見,僅供參考,請多多指教,我這邊也會持續修正加更新) 介紹一下snabbdom基本用法 介紹一下snabbdo...
摘要:總共寫了四篇文章都是自己的一些拙見,僅供參考,請多多指教,我這邊也會持續修正加更新介紹一下基本用法介紹一下渲染原理介紹一下的算法和對值的認識介紹一下對于兼容的修改這篇主要是記錄一下針對做了哪些修改增加用來兼容某些功能函數,例如等將每個文件單 總共寫了四篇文章(都是自己的一些拙見,僅供參考,請多多指教,我這邊也會持續修正加更新) 介紹一下snabbdom基本用法 介紹一下snabbdo...
摘要:如果新舊的和都相同,說明兩個相似,我們就可以保留舊的節點,再具體去比較其差異性,在舊的上進行打補丁否則直接替換節點。 總共寫了四篇文章(都是自己的一些拙見,僅供參考,請多多指教,我這邊也會持續修正加更新) 介紹一下snabbdom基本用法 介紹一下snabbdom渲染原理 介紹一下snabddom的diff算法和對key值的認識 介紹一下對于兼容IE8的修改 這篇我將以自己的思路去...
閱讀 695·2021-11-15 11:37
閱讀 3316·2021-10-27 14:14
閱讀 6038·2021-09-13 10:30
閱讀 2961·2021-09-04 16:48
閱讀 1926·2021-08-18 10:22
閱讀 2125·2019-08-30 14:19
閱讀 729·2019-08-30 10:54
閱讀 1745·2019-08-29 18:40