成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

【干貨】vue源代碼簡(jiǎn)單解析

ccj659 / 2579人閱讀

摘要:解析器的狀態(tài)機(jī)設(shè)計(jì)首先要說文件夾里有各種財(cái)寶等著大家挖掘認(rèn)真看一看一定不會(huì)后悔的主要的職責(zé)是可以把一個(gè)數(shù)據(jù)里的某一個(gè)路徑下的數(shù)據(jù)取出來,比如所以對(duì)字符串的解析成為了它的關(guān)鍵。

最近饒有興致的又把最新版 Vue.js 的源碼學(xué)習(xí)了一下,覺得真心不錯(cuò),個(gè)人覺得 Vue.js 的代碼非常之優(yōu)雅而且精辟,作者本身可能無 (bu) 意 (xie) 提及這些。那么,就讓我來吧:)

程序結(jié)構(gòu)梳理

Vue 程序結(jié)構(gòu)

Vue.js 是一個(gè)非常典型的 MVVM 的程序結(jié)構(gòu),整個(gè)程序從最上層大概分為

全局設(shè)計(jì):包括全局接口、默認(rèn)選項(xiàng)等
vm 實(shí)例設(shè)計(jì):包括接口設(shè)計(jì) (vm 原型)、實(shí)例初始化過程設(shè)計(jì) (vm 構(gòu)造函數(shù))
這里面大部分內(nèi)容可以直接跟 Vue.js 的官方 API 參考文檔對(duì)應(yīng)起來,但文檔里面沒有且值得一提的是構(gòu)造函數(shù)的設(shè)計(jì),下面是我摘出的構(gòu)造函數(shù)最核心的工作內(nèi)容。

Vue 實(shí)例初始化

整個(gè)實(shí)例初始化的過程中,重中之重就是把數(shù)據(jù) (Model) 和視圖 (View) 建立起關(guān)聯(lián)關(guān)系。Vue.js 和諸多 MVVM 的思路是類似的,主要做了三件事:

通過 observer 對(duì) data 進(jìn)行了監(jiān)聽,并且提供訂閱某個(gè)數(shù)據(jù)項(xiàng)的變化的能力
把 template 解析成一段 document fragment,然后解析其中的 directive,得到每一個(gè) directive 所依賴的數(shù)據(jù)項(xiàng)及其更新方法。比如 v-text="message" 被解析之后 (這里僅作示意,實(shí)際程序邏輯會(huì)更嚴(yán)謹(jǐn)而復(fù)雜):
所依賴的數(shù)據(jù)項(xiàng) this.$data.message,以及
相應(yīng)的視圖更新方法 node.textContent = this.$data.message
通過 watcher 把上述兩部分結(jié)合起來,即把 directive 中的數(shù)據(jù)依賴訂閱在對(duì)應(yīng)數(shù)據(jù)的 observer 上,這樣當(dāng)數(shù)據(jù)變化的時(shí)候,就會(huì)觸發(fā) observer,進(jìn)而觸發(fā)相關(guān)依賴對(duì)應(yīng)的視圖更新方法,最后達(dá)到模板原本的關(guān)聯(lián)效果。
所以整個(gè) vm 的核心,就是如何實(shí)現(xiàn) observer, directive (parser), watcher 這三樣?xùn)|西

文件結(jié)構(gòu)梳理

Vue.js 源代碼都存放在項(xiàng)目的 src 目錄中,我們主要關(guān)注一下這個(gè)目錄 (事實(shí)上 test/unit/specs 目錄也值得一看,它是對(duì)應(yīng)著每個(gè)源文件的測(cè)試用例)。

src 目錄下有多個(gè)并列的文件夾,每個(gè)文件夾都是一部分獨(dú)立而完整的程序設(shè)計(jì)。不過在我看來,這些目錄之前也是有更立體的關(guān)系的:

Vue 文件結(jié)構(gòu)

首先是 api/* 目錄,這幾乎是最“上層”的接口封裝,實(shí)際的實(shí)現(xiàn)都埋在了其它文件夾里
然后是 instance/init.js,如果大家希望自頂向下了解所有 Vue.js 的工作原理的話,建議從這個(gè)文件開始看起
instance/scope.js:數(shù)據(jù)初始化,相關(guān)的子程序 (目錄) 有 observer/*、watcher.js、batcher.js,而 observer/dep.js 又是數(shù)據(jù)觀察和視圖依賴相關(guān)聯(lián)的關(guān)鍵
instance/compile.js:視圖初始化,相關(guān)的子程序 (目錄) 有 compiler/、directive.js、parsers/
其它核心要素:directives/、element-directives/、filters/、transition/
當(dāng)然還有 util/* 目錄,工具方法集合,其實(shí)還有一個(gè)類似的 cache.js
最后是 config.js 默認(rèn)配置項(xiàng)
篇幅有限,如果大家有意“通讀” Vue.js 的話,個(gè)人建議順著上面的整體介紹來閱讀賞析。

接下來是一些自己覺得值得一提的代碼細(xì)節(jié)

一些不容錯(cuò)過的代碼/程序細(xì)節(jié)

this._eventsCount 是什么?

一開始看 instance/init.js 的時(shí)候,我立刻注意到一個(gè)細(xì)節(jié),就是 this._eventsCount = {} 這句,后面還有注釋

eventsCount1

for $broadcast optimization

非常好奇,然后帶著疑問繼續(xù)看了下去,直到看到 api/events.js 中 $broadcast 方法的實(shí)現(xiàn),才知道這是為了避免不必要的深度遍歷:在有廣播事件到來時(shí),如果當(dāng)前 vm 的 _eventsCount 為 0,則不必向其子 vm 繼續(xù)傳播該事件。而且這個(gè)文件稍后也有 _eventsCount 計(jì)數(shù)的實(shí)現(xiàn)方式。

eventsCount2

eventsCount3

這是一種很巧妙同時(shí)也可以在很多地方運(yùn)用的性能優(yōu)化方法。

數(shù)據(jù)更新的 diff 機(jī)制

前陣子有很多關(guān)于視圖更新效率的討論,我猜主要是因?yàn)?virtual dom 這個(gè)概念的提出而導(dǎo)致的吧。這次我詳細(xì)看了一下 Vue.js 的相關(guān)實(shí)現(xiàn)原理。

實(shí)際上,視圖更新效率的焦點(diǎn)問題主要在于大列表的更新和深層數(shù)據(jù)更新這兩方面,而被熱烈討論的主要是前者 (后者是因?yàn)樾枨笮∵€是沒爭(zhēng)議我就不得而知了)。所以這里著重介紹一下 directives/repeat.js 里對(duì)于列表更新的相關(guān)代碼。

diff1

首先 diff(data, oldVms) 這個(gè)函數(shù)的注釋對(duì)整個(gè)比對(duì)更新機(jī)制做了個(gè)簡(jiǎn)要的闡述,大概意思是先比較新舊兩個(gè)列表的 vm 的數(shù)據(jù)的狀態(tài),然后差量更新 DOM。

diff2

第一步:便利新列表里的每一項(xiàng),如果該項(xiàng)的 vm 之前就存在,則打一個(gè) _reused 的標(biāo) (這個(gè)字段我一開始看 init.js 的時(shí)候也是困惑的…… 看到這里才明白意思),如果不存在對(duì)應(yīng)的 vm,則創(chuàng)建一個(gè)新的。

diff3

第二步:便利舊列表里的每一項(xiàng),如果 _reused 的標(biāo)沒有被打上,則說明新列表里已經(jīng)沒有它了,就地銷毀該 vm。

diff4

第三步:整理新的 vm 在視圖里的順序,同時(shí)還原之前打上的 _reused 標(biāo)。就此列表更新完成。

順帶提一句 Vue.js 的元素過渡動(dòng)畫處理 (v-transition) 也設(shè)計(jì)得非常巧妙,感興趣的自己看吧,就不展開介紹了

組件的 [keep-alive] 特性

keepAlive1

keepAlive2

Vue.js 為其組件設(shè)計(jì)了一個(gè) [keep-alive] 的特性,如果這個(gè)特性存在,那么在組件被重復(fù)創(chuàng)建的時(shí)候,會(huì)通過緩存機(jī)制快速創(chuàng)建組件,以提升視圖更新的性能。代碼在 directives/component.js。

數(shù)據(jù)監(jiān)聽機(jī)制

如何監(jiān)聽某一個(gè)對(duì)象屬性的變化呢?我們很容易想到 Object.defineProperty 這個(gè) API,為此屬性設(shè)計(jì)一個(gè)特殊的 getter/setter,然后在 setter 里觸發(fā)一個(gè)函數(shù),就可以達(dá)到監(jiān)聽的效果。

不過數(shù)組可能會(huì)有點(diǎn)麻煩,Vue.js 采取的是對(duì)幾乎每一個(gè)可能改變數(shù)據(jù)的方法進(jìn)行 prototype 更改:

ob_array1

但這個(gè)策略主要面臨兩個(gè)問題:

無法監(jiān)聽數(shù)據(jù)的 length,導(dǎo)致 arr.length 這樣的數(shù)據(jù)改變無法被監(jiān)聽
通過角標(biāo)更改數(shù)據(jù),即類似 arr[2] = 1 這樣的賦值操作,也無法被監(jiān)聽
為此 Vue.js 在文檔中明確提示不建議直接角標(biāo)修改數(shù)據(jù)

同時(shí) Vue.js 提供了兩個(gè)額外的“糖方法” $set 和 $remove 來彌補(bǔ)這方面限制帶來的不便。整體上看這是個(gè)取舍有度的設(shè)計(jì)。我個(gè)人之前在設(shè)計(jì)數(shù)據(jù)綁定庫(kù)的時(shí)候也采取了類似的設(shè)計(jì) (一個(gè)半途而廢的內(nèi)部項(xiàng)目就不具體獻(xiàn)丑了),所以比較認(rèn)同也有共鳴。

path 解析器的狀態(tài)機(jī)設(shè)計(jì)

首先要說 parsers 文件夾里有各種“財(cái)寶”等著大家挖掘!認(rèn)真看一看一定不會(huì)后悔的

parsers/path.js 主要的職責(zé)是可以把一個(gè) JSON 數(shù)據(jù)里的某一個(gè)“路徑”下的數(shù)據(jù)取出來,比如:

var path = "a.b[1].v"
var obj = {
  a: {
    b: [
      {v: 1},
      {v: 2},
      {v: 3}
    ]
  }
}
parse(obj, path) // 2

所以對(duì) path 字符串的解析成為了它的關(guān)鍵。Vue.js 是通過狀態(tài)機(jī)管理來實(shí)現(xiàn)對(duì)路徑的解析的:

咋一看很頭大,不過如果再稍微梳理一下:

也許看得更清楚一點(diǎn)了,當(dāng)然也能發(fā)現(xiàn)其中有一點(diǎn)小問題,就是源代碼中 inIdent 這個(gè)狀態(tài)是具有二義性的,它對(duì)應(yīng)到了圖中的三個(gè)地方,即 in ident 和兩個(gè) in (quoted) ident。

總結(jié)

Vue.js 里的代碼細(xì)節(jié)還不僅于此,比如:

cache.js 里的緩存機(jī)制設(shè)計(jì)和場(chǎng)景運(yùn)用 (如在 parsers/path.js 中)
parsers/template.js 里的 cloneNode 方法重寫和對(duì) HTML 自動(dòng)補(bǔ)全機(jī)制的兼容
在開發(fā)和生產(chǎn)環(huán)境分別用注釋結(jié)點(diǎn)和不可見文本結(jié)點(diǎn)作為視圖的“占位符”等等
自己也在閱讀代碼,了解 Vue.js 的同時(shí)學(xué)到了很多東西,同時(shí)我覺得代碼實(shí)現(xiàn)只是 Vue.js 優(yōu)秀的要素之一,整體的程序設(shè)計(jì)、API 設(shè)計(jì)、細(xì)節(jié)的取舍、項(xiàng)目的工程考量都非常棒!

總之,分享一些自己的收獲和代碼的細(xì)節(jié),希望可以幫助大家開闊思路,提供靈感

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/87291.html

相關(guān)文章

  • 干貨--手把手?jǐn)]vue移動(dòng)UI框架: 滑動(dòng)加載

    摘要:前言在我們移動(dòng)端還有一個(gè)很常用的組件,那就是滑動(dòng)加載更多組件。平常我們看到的很多插件實(shí)現(xiàn)相當(dāng)復(fù)雜就覺得這個(gè)組件很難,其實(shí)不是的這個(gè)組件其實(shí)可以很簡(jiǎn)單的就實(shí)現(xiàn)出來,而且體驗(yàn)也能非常的棒當(dāng)然我們沒有實(shí)現(xiàn)下拉刷新功能下面我們就一起來實(shí)現(xiàn)這個(gè)組件。 前言 在我們移動(dòng)端還有一個(gè)很常用的組件,那就是滑動(dòng)加載更多組件。平常我們看到的很多插件實(shí)現(xiàn)相當(dāng)復(fù)雜就覺得這個(gè)組件很難,其實(shí)不是的??!這個(gè)組件其實(shí)可...

    Harpsichord1207 評(píng)論0 收藏0
  • 做IT這幾年,我整理了這些干貨想要送給你!

    摘要:資源獲取方式根據(jù)下面的索引,大家可以選擇自己需要的資源,然后在松哥公眾號(hào)牧碼小子后臺(tái)回復(fù)對(duì)應(yīng)的口令,就可以獲取到資源的百度云盤下載地址。公眾號(hào)二維碼如下另外本文會(huì)定期更新,松哥有新資源的時(shí)候會(huì)及時(shí)分享給大家,歡迎各位小伙伴保持關(guān)注。 沒有一條路是容易的,特別是轉(zhuǎn)行計(jì)算機(jī)這條路。 松哥接觸過很多轉(zhuǎn)行做開發(fā)的小伙伴,我了解到很多轉(zhuǎn)行人的不容易,記得松哥大二時(shí)剛剛決定轉(zhuǎn)行計(jì)算機(jī),完全不知道這...

    王晗 評(píng)論0 收藏0
  • JavaScript精編干貨

    摘要:老姚淺談怎么學(xué)鑒于時(shí)不時(shí),有同學(xué)私信問我老姚,下同怎么學(xué)前端的問題。擼碼聽歌,全局控制。 淺析用 js 解析 xml 的方法 由于項(xiàng)目上需要解析 xml,于是各種百度,然后自己總結(jié)了下各個(gè)主流瀏覽器解析 xml 的方法,只能是很淺顯的知道他的用法,但是還沒有深層次的研究。 裝 X - 建立自己的斗圖網(wǎng)站庫(kù) 之前加過一個(gè)斗圖群,看到很多經(jīng)典的表情,然后就收藏到了 QQ, 迫于本屌絲開不起...

    Fourierr 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<