剛到家疫情就開始爆發,恰巧家裡沒有網,手機網路在老家的速度就像拖拉機,每天躲在家裡,還好剛到老家時搞了些口罩,不至於返程時沒有口罩可帶。
手機的網路速度到底什麼樣呢,用vue-cli建個專案就在那一直install,還有可能中途失敗,哎。。。,沒法練習vue了就把自己寫好的簡易版vue拿出來又擼了擼,還有點意思。
當時寫這個的時候,還看了挺多其他前輩的部落格,但是真是記不清都看了誰的。。。在此先致敬一下。嘻嘻!!
vue原始碼也是看了看,講真大部分看不懂,也許還是沒到那個級別。
首先老規矩要封閉作用域。
建立vue類
我這裡就叫tempvue
(
function
(global, tempvue))(
this
,function()
}})
把一些資料初始化一下,並且把data、methods等掛載到this上
class
tempvue
// 資料初始化函式
observe
(data));
}// **函式
proxy
(data =),
get()}
)})}
// 資料響應函式(資料劫持)
definereactive
(data, key, val)
,set
(newvalue)})
;}}
到這裡呢我們就實現了資料劫持,當訪問資料和改變資料時,我們就可以做相應的渲染等工作了。
我們想要在資料改變時做相應的工作,就建立相應的觀察者。
也就是實現對這種操作的監控。
export
default},
methods:
}}
那我們要怎麼監控它呢? 上**
// dep: 管理watcher 這單詞啥意思沒搞懂就看原始碼這麼寫的
class
dep// 新增資料依賴
addsub
(sub)
// 呼叫依賴的upload函式 資料更新
notify()
}// watcher觀察資料變化
class
watcher
// 更新資料
update()
}
到這小夥伴可能有點雲裡霧裡,一呢是因為這玩意確實有點繞,二來呢鄙人的表達能力確實欠妥,現在呢有乙個最直接的問題就是這個watcher什麼時候建立例項呢,又是如何做到監控資料的呢?
虛擬dom這個概念相信前端的小夥伴們都不會陌生,在主流的框架裡都有這個概念,說來說去都是要加強效能云云的。
廢話不多說直接上**:
// 編譯器
class
compile
}// 建立dom樹
domfragment
(node)
else if (node.childnodes[i].nodetype === 3) else
// }
// 遍歷node的childnodes
let childarr = array.prototype.slice.
call
(node.childnodes,0)
;// 遍歷dom節點
childarr.
foreach
(item =>
elseif(
this
.iseltext
(item))}
)return temp;
}// 編譯函式
compile
(node)if(
this
.iselement
(node.dom)))
; node.childnodes.
foreach
(ele =>);
}else})
;}}// 解析指令
comdirective
(attrkey, attrval, node)if(
this
.isevent
(attrkey))if
(this
.isbind
(attrkey))}
// 是不是t-的指令
isdirective
(attr)
// 是不是@開頭的事件繫結
isevent
(attr)
// 是不是:開頭的資料繫結
isbind
(attr)
// 是不是dom節點
iselement
(node)
isstr
(val)
// 是不是文字節點
iseltext
(node)
// 插值文字
isinterpolation
(node)\}/
.test
(node);}
// 繫結事件 嗯 這裡沒有匹配那種控制代碼寫法
bindevent
(dir, exp, vm, node)
}// 解析 : 資料繫結
bindvalue
(dir, exp, vm, node)
let value =
this
.isstr
(exp)
? exp.
replace
(/'|"/g,''
):analysisinterpolation
(exp, vm.$data, vm.$data)
node.dom.
setattribute
(dir, value)
removeattr
(node, dir,
':')
}// 解析插值文字
compiletext
(node)
// style繫結
bindstyle
(exp, vm, node)/g,
'');// let style = str.split(',').join(';') + ';';
let stylearr = str.
split
(',');
stylearr.
foreach
(prop =>)}
else)}
}// 更新函式
update
(node, vm, exp, dir));
}textupdater
(node, value)
modelupdater
(node, value)
htmlupdater
(node, value)
render
(node, val, exp)if(
this
.iselement
(node.dom))}
else
}// 解析t-text
text
(node, vm, attrval)
// 解析t-model
model
(node, vm, attrval))}
// 解析t-html
html
(node, vm, attrval)
}// 虛擬dom樹
class
vnode
// 新增虛擬dom 節點
(node)
this
.childnodes.
push
(node)
}// 模板
(temp)
// 匹配} 插值語法
isinterpolation
(text)
}/g)
;return matelist ===
null?[
]: matelist;
}}
上面這段**呢,我把建立vdom和虛擬dom樹還有解析功能寫到了一起,這不重要,重要的是剛才提出那個問題,就是watcher在**使用的?
compile類中有乙個update方法這個方法呢在首次載入是會被觸發一次,每個指令或模版字串被讀取時都要觸發,在觸發時就會new watcher
建立乙個watcher例項然後會把它掛載到dep的靜態屬性上,可是然後呢?這裡我們要簡單的改造一下tempvue類:
class
tempvue
// 資料初始化函式
observe
(data));
}// **函式
proxy
(data =),
get()}
)})}
// 資料響應函式(資料劫持)
definereactive
(data, key, val)
,set
(newvalue)})
;}}
嗯哼,再來捋一下邏輯,首次讀取指令或模版字串時,new watcher
建立watcher例項然後把它掛載到dep的靜態屬性target上,然後觸發資料劫持的get方法,在get方法中把target通過dep的例項addsub方法駕到依賴佇列中,在修改資料時在觸發dep例項的notify方法來更新。
嘻嘻大概就是這樣,vdom那一塊我就不多做解釋了。
有大bug歡迎大神們來拍磚,下附gitee,為啥不是github呢,因為前一段github上不去。。。。
碼雲:
基於vue搭建乙個簡易版豆瓣
前段日子業餘時看了下vue,想著怎麼也得寫個例項來加深一下,於是便基於vue構建了乙個簡易版豆瓣。由於工作中使用的並不是vue框架,對vue的了解也不夠深入,這也是本人第一次寫技術博文,因此,有紕漏之處還請大家批評指正。專案簡介 本專案主要是基於vue,構建乙個簡易版豆瓣,實現將讀書 電影 同城活動...
實現乙個簡易版的Tomcat 十二
如何解析xml檔案?這裡會用到dom4j解析,如下 通過解析config目錄下的web.xml檔案 並將其中的中間的文字作為key 將中間的文字作為value try catch exception e 根據給定的資源字尾名獲取對應的content type的值 param ext return p...
從頭實現乙個簡易版React(一)
工作中使用react也很長一段時間了,雖然對它的用法,原理有了一定的了解,但是總感覺停留在表面。本著知其然知其所以然的態度,我試著去看了react原始碼,幾天下來,發現並不能看懂,反而更加雲裡霧裡了 既然看不懂,那就看看社群前輩們寫的一些原始碼分析文章以及實現思路吧,又這麼過了幾天,總算是摸清點思路...