寫乙個自己的簡易版vue

2021-10-02 11:35:48 字數 4869 閱讀 1500

剛到家疫情就開始爆發,恰巧家裡沒有網,手機網路在老家的速度就像拖拉機,每天躲在家裡,還好剛到老家時搞了些口罩,不至於返程時沒有口罩可帶。

手機的網路速度到底什麼樣呢,用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原始碼,幾天下來,發現並不能看懂,反而更加雲裡霧裡了 既然看不懂,那就看看社群前輩們寫的一些原始碼分析文章以及實現思路吧,又這麼過了幾天,總算是摸清點思路...