成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

【干貨】vue源代碼簡單解析

ccj659 / 2535人閱讀

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

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

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

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

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

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

Vue 實例初始化

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

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

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

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

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

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

首先是 api/* 目錄,這幾乎是最“上層”的接口封裝,實際的實現(xiàn)都埋在了其它文件夾里
然后是 instance/init.js,如果大家希望自頂向下了解所有 Vue.js 的工作原理的話,建議從這個文件開始看起
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/
當然還有 util/* 目錄,工具方法集合,其實還有一個類似的 cache.js
最后是 config.js 默認配置項
篇幅有限,如果大家有意“通讀” Vue.js 的話,個人建議順著上面的整體介紹來閱讀賞析。

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

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

this._eventsCount 是什么?

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

eventsCount1

for $broadcast optimization

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

eventsCount2

eventsCount3

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

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

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

實際上,視圖更新效率的焦點問題主要在于大列表的更新和深層數(shù)據(jù)更新這兩方面,而被熱烈討論的主要是前者 (后者是因為需求小還是沒爭議我就不得而知了)。所以這里著重介紹一下 directives/repeat.js 里對于列表更新的相關(guān)代碼。

diff1

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

diff2

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

diff3

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

diff4

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

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

組件的 [keep-alive] 特性

keepAlive1

keepAlive2

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

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

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

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

ob_array1

但這個策略主要面臨兩個問題:

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

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

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

首先要說 parsers 文件夾里有各種“財寶”等著大家挖掘!認真看一看一定不會后悔的

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

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

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

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

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

總結(jié)

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

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

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

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

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/87291.html

相關(guān)文章

  • 干貨--手把手擼vue移動UI框架: 滑動加載

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

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

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

    王晗 評論0 收藏0
  • JavaScript精編干貨

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

    Fourierr 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<