以前對看過比較多關於vue源碼的文章,可是對於總體框架和流程仍是有些模糊,最後用chrome debug對vue的源碼進行查看整理出這篇文章。。。。javascript
本文對vue的總體框架和總體流程進行簡要的分析,不對某些具體的細節進行分析,全部須要對vue有初步的認識,包括對Object.defineProperty、虛擬DOM有必定了解,本文不會對Object.defineProperty、虛擬DOM的原理和細節進行分析。
vue大致能夠分兩個部分:
1.採用Object.defineProperty進行數據的雙向綁定;
2.採用虛擬DOM技術進行視圖渲染;vue
vue構造函數調用了this._init(options)方法,這個方法在initMixin中,如上圖所示,進入initMixin
initMixin主要完成數據的初始化和視圖的初始化:
1.數據初始化主要是數據的observe,在上圖的initState中進行;
2.視圖的初始化在vm.$mount(vm.$options.el),其中vm爲Vue的實例,watcher的設置也是在vm.$mount(vm.$options.el)中完成的;
咱們能夠看到這裏定義了beforeCreated和created這兩個鉤子函數。java
接着上面咱們看看數據初始化都作了什麼,進入initState
這裏咱們主要對數據進行操做的是initData,傳入的是vm,咱們來具體看看initData:
咱們先忽略前面的一些邏輯判斷,主要看兩個地方:
1.數據代理,主要是將_data的數據代理到vm上,這樣的話能夠直接對vm上的數據進行修改;
2.數據observe,傳入data;
咱們先看看vue怎麼對數據進行observe的,進入observe
在observe裏返回的是ob,也就是Observer類的實例,咱們看看Observer類是怎麼定義的,進入Observer類
如上圖在對data進行observe時對數組進行了特殊的處理,這塊咱們先不看,先看通常狀況下的處理,即調用this.walk(value)
walk主要對data的屬性進行遍歷,進入defineReactive
能夠看到Object.defineProperty是在這裏對屬性設置get和set的,其中get主要進行依賴收集,其實就是在收集視圖渲染的watcher,後面會提到,set主要是數據更新時進行視圖的更新
至此,數據的初始化就完成了,從上面的分析來看,數據的初始化主要的工做就是對數據進行observe。git
接着上面,在vue入口那裏,咱們知道視圖的掛載主要是調用了vm.$mount(vm.$options.el)
如圖,因此咱們進入vm.$mount,看看裏面都幹了啥,在源碼裏面有兩處地方涉及到$mount
這是第一處,就是return mountComponent
這是第二處,上面兩個圖是一塊兒的,屏幕大小有限,因此截了兩個圖。。。
我們看看第二處,裏面作了一個處理,就是將template編譯成render函數,在vue的教程裏有render函數的使用,這裏咱們能夠看出咱們在組件裏定義render函數會比定義template快,由於在定義template的組件掛載時多了一步將template編譯成render函數;
第二處的return 仍是調用了第一處,因此咱們看看第一處調用的mountComponent方法,進入mountComponent
上面兩個圖是一塊兒的,屏幕大小有限,因此截了兩個圖。。。
這裏咱們能夠看到定義了兩個鉤子beforeMount和mount,中間調用了watcher,咱們看一下這裏watcher的定義,這裏標註的不太好,擋住了。。。咱們看看watcher的這行代碼:
github
vm._watcher=new Watcher(vm,updateComponent,noop)
咱們能夠看到Watcher類主要傳入了vm,updateComponent,noop三個參數,其中updateComponent的主要做用是將虛擬DOM轉化爲真實的DOM並進行掛載,具體的細節下面在討論,咱們下面看看Watcher類是怎麼定義的,進入Watcher
這裏咱們注意兩個地方,一個是this.getter的定義,這裏就是上面傳進來的updateComponent,還有就是執行this.get(),咱們進入這個get方法
這裏咱們看到首先收集的依賴是當前watcher實例,而後調用getter方法也就是updateComponent方法,以前咱們對updateComponent方法的做用進行了簡單的說明,這裏咱們具體看看updateComponent都幹了啥,進入updateComponent:
這裏調用了vm._update方法,其中傳入的參數有vm._render(),_render函數主要的做用是產生虛擬DOM,進入_update
這裏主要是將虛擬DOM轉化爲真實DOM並進行掛載,分兩種狀況,分別是有舊的虛擬DOM和無舊的虛擬DOM,對應初始化時調用仍是數據更新時調用,這裏定義了一個鉤子beforeUpdate
到這裏,視圖的初始化和掛載也結束了,下面看看數據變化時視圖是如何更新的chrome
接着上面咱們看看數據變化時視圖是怎麼變化的,在數據初始化的時候,咱們知道數據變化時將觸發set方法,以下圖:
上圖能夠看出,set最後調用了dep.notify,進入notify
如上圖,notify主要將收集的依賴,也就是收集的全部watcher,調用全部watcher的update方法,咱們看看watcher的updata方法幹了啥
這裏就是調用了queueWatcher,進入queueWatcher
這裏採用隊列異步更新,就是講=將watcher push進隊列queue中,而後執行nextTick方法,進入nextTick
上面兩個圖是一塊兒的,屏幕大小有限,因此截了兩個圖。。。
這個部分有點難看,cb爲傳入的flushSchedulerQueue函數,執行timerFunc,將nextTickHander加入異步隊列,執行nextTickHander,執行cb,既執行flushSchedulerQueue,進入flushSchedulerQueue
上面兩個圖是一塊兒的,屏幕大小有限,因此截了兩個圖。。。
主要看watcher.run(),進入watcher.run
執行了this.get(),即進入前面數據渲染和掛載的地方
到這裏,vue整個的執行流程基本就結束了。segmentfault
盜用一下vue官網關於vue生命週期的圖,對照以前的內容梳理一下:
對照上面的分析基本上能夠找到各個鉤子函數的位置,下面那個銷燬的我就沒用作分析了。。。數組
你們有興趣的話能夠關注一下個人博客框架