Vue生命周期是指vue實例對象從創建之初到銷毀的過程,掌握和理解生命周期過程中每一個步驟的作用,可以更加合理的安排我們不同業務邏輯具體的執行位置。
-
beforeCreate在官方文檔描述中說,在做一些數據監視和事件初始化,這里有一個容易讓人走偏的地方,就是事件初始化,其實就是為vue對象添加一些屬性,就是methods中的一些函數全部作為vue對象的屬性存在,Vue會講所有的data數據和methods中的函數添加到創建的vue對象上面。
-
created 這個方法表示,vue對象已經創建成功,這里要搞清楚vue對象並不是我們所說的虛擬dom,vue對象就是一個js對象,他內部只是對數據進行操作,通過對數據的操作進而影響到虛擬dom的構建,所以在這個方法中我們可以做一些數據初始化工作,最常見的就是發送ajax請求來對已經構建完畢的vue對象的靜態屬性進行一些初始化
-
compile 這個方法是正真開始構建虛擬dom,這里值得注意的地方是,虛擬dom和真實dom的差別,說到這里相信許多同學跟我一樣有很多疑惑,既然已經有虛擬dom了為什么還要構建真實dom,我們操作了虛擬dom以后直接appendChild不行嘛。答案是no, 虛擬dom並不是dom,他只是描述了一個dom結構,編譯模版的過程(模版有兩種來源,這里不述),就是根據模版的html結構來創建虛擬dom的過程,如果大家沒沒懂,那么請看以下代碼:
* 模版結構
> <ul class=”list”> > <li>item 1</li> > <li>item 2</li> > </ul>
* 根據模版結構生成的虛擬dom結構,>{ type: ‘ul’, props: { ‘class’: ‘list’ }, children: [ > { type: ‘li’, props: {}, children: [‘item 1’] }, > { type: ‘li’, props: {}, children: [‘item 2’] } >] }
以上代碼時不是清晰明了,虛擬dom只是描述了一種數據結構,他並不代表真實的dom對象,他只是描述了一個dom tree該有的組織方式,編譯的過程就是根據模版結構生成dom數據結構的方式,高大上一點叫做虛擬dom。 Sumarry一下: - Virtual DOM is any kind of representation of a real DOM (虛擬dom只是真實dom的一個代表) - When we change something in our Virtual DOM Tree, we get a new Virtual Tree. Algorithm compares these two trees (old and new), finds differences and makes only necessary small changes to real DOM so it reflects virtual (如果我們在虛擬dom中對數據做了修改,我們會得到一個新的虛擬dom結構,算法比較這兩顆dom樹,找到不同之處,只需要在真實dom中做必要的修改來對應虛擬DOM)在編譯期間我們要做的就是根據模版DOM結構來構造一個數據結構來對應模版html結構
-
beforeMount 這個過程就是根據編譯以后產生的虛擬dom結構來構造一個真實的dom結構,再說一遍,這兩個dom有很大的區別,前者只表示數據結構,后者可以直接添加到html文檔結構中來渲染一個效果。在這個期間,我們就可以操作真實的dom對象了,包括我們為某一個特定的dom節點綁定事件,標簽屬性,內容的操作等,例如使用select2來修飾select,但是並不推薦在這里進行一些事件綁定或者dom操作,因為在這期間,Vue還要做一件非常重要的事情就是通過Vue自己的方式來標識每一個真實的dom節點,我們在vue里一般都是通過$els或者$refs來操作對應的dom元素,但是這期間正是標注所有元素的過程,很有可能會出一些意想不到的錯誤。
-
mounted 見名知意,掛載,表示真實dom已經夠早完畢,我們可以append到父容器當中來構造頁面了,在這里我們就可以完成一些對於真實dom的操作,不論是直接訪問dom的屬性內容或者事件的綁定,都可以在這里放心大膽的做了,一般情況下我們不需要直接操作dom,Vue也不推薦這么做,但是這里你需要知道的事如果你有這種需求,完全可以在這里完成,掛載的過程就是將生成的真實DOM對象append到掛載點下面,就是appendChild的過程,這個時候的虛擬dom結構根生成出來的real dom結構一模一樣,我們以后要操作的就是這個虛擬dom結構,就是前面根據模版生成出來的dom數據結構。
-
beforeUpdate這個方法在整個生命周期之中也只被調用一次,在做什么呢,想一想上面所做的事情,上面是根據模版構造出來一個真實的dom對象,到現在他並沒有跟我們的vue實例對象扯上關系,怎么通過我們的vue實例來影響到真實的dom對象呢,怎么把我們的數據綁定的真實dom當中了,以后我們只需要操作數據就可以影響到dom結構的渲染呢?在這個方法里,Vue同樣依據前面的規則根據vue實例提供的數據在模版中的位置來重新生成一個虛擬dom數據結構,沒錯,你沒看錯,我們要生成兩個虛擬dom,前一個dom只是dom結構,並沒有綁定我們vue的屬性數據,這一個dom是綁定了我們vue實例數據的dom結構,在這個dom生成的過程中,vue根據自己的語法規則,對比如指令,表達式之類的東西進行替換,生成一個新的虛擬dom結構,接下來我們要做什么,我想大家應該所料不錯,沒錯,鼻孔朝天的那位同學說的很對,就是進行比較兩個虛擬dom之間存在的差異。請不要走開,廣告之后更加精彩。。。。。
-
update,接着上一集,我們繼續吹,這個方法在我們整個生命周期之內會反復調用,你會發現,每一次對vue對象的變更都會觸發update方法,他做了什么呢,他就是在反復的生成一個virtual dom,生成的新dom不斷跟之前的dom結構進行比對,這里又一個比較高大上的比對算法,叫differ,我想在座各位同學是不是有一種恍然大悟的趕腳,前面幾集我說過,Vue在beforeMount的時候會對每一個dom節點進行標記,他為了什么嘞? 你懂了沒有呢?不懂去面壁,Vue對每一個節點進行標記就是為了更加快速准確的定位dom節點。。。
用一種更加清楚明了的總結方式就是代碼:
// 1. 構建虛擬DOM var tree = el('div', {'id': 'container'}, [ el('h1', {style: 'color: blue'}, ['simple virtal dom']), el('p', ['Hello, virtual-dom']), el('ul', [el('li')]) ]) // 2. 通過虛擬DOM構建真正的DOM var root = tree.render() document.body.appendChild(root) // 3. 生成新的虛擬DOM var newTree = el('div', {'id': 'container'}, [ el('h1', {style: 'color: red'}, ['simple virtal dom']), el('p', ['Hello, virtual-dom']), el('ul', [el('li'), el('li')]) ]) // 4. 比較兩棵虛擬DOM樹的不同 var patches = diff(tree, newTree) // 5. 在真正的DOM元素上應用變更 patch(root, patches)
至於之后的所有方法我想就不必深究了,他其實就是vue實例對象生成的一個逆過程,一句話來說就是:潮水怎么來就怎么退去。。
-
接着來聊一下性能問題。很多同學可能在想既然他存在dom操作,肯定性能會受到影響,但是這跟坊間傳言優點不符啊,坊間都說虛擬dom性能高渲染快,但是為什么存在大量dom操作呢?接下來呢我就要跟你聊一聊瀏覽器的大致組成和你通過原聲js做這些適時數據綁定所要做的一些事情了。咸鹽少許。。。
這里引用一位老兄在知乎上的回答,我感覺說的很對也很明了,虛擬dom為什么很快:- JavaScript執行速度很快
- Dom操作很慢
Chrome剛出來的時候,在Chrome里跑Javascript非常快,給了其它瀏覽器很大壓力。而現在經過幾輪你追我趕,各主流瀏覽器的Javascript執行速度都很快了。但是遺憾的是瀏覽器廠商只對Javascript引擎進行也極限優化,但是對html文檔結構的構建速度和css樣式的渲染並沒有多少進步,就是說dom引擎和css引擎的發展速度遠遠更不上js引擎解析js腳本的速度,這就比較尷尬了,因為js很多時候都是為了操作dom節點和修飾dom,由於html文檔結構重新排布的速度遠遠沒有js執行速度快,這在很多時候就造成了難以理解的邏輯錯誤,稱為難以言說的痛。。。。於是在這種情況下,虛擬dom應用而生了,虛擬dom說白了就是一個js結構的對象,他內部的數據組織方式是按照html文檔結構組成的樹狀結構,我們通過每一次數據的修改來重新構造一個js對象,根據前后對象之間的比對就可以發現具體那個節點發生了變化,然后在真實的dom結構中迅速的定位到元素,進行修改,最小化真實dom的重排和重繪。如果你通過原聲js,每次修改dom結構或者內容,你必須從頭到尾進行dom節點遍歷,造成很大的時間和資源的浪費,這是一點,還有一點就是每一次dom操作導致的結構重新排布,所以最好的dom操作方式是一次性把要修改的東西全部做完,進行一次性行更新。而虛擬dom做到了這一點,盡量少操作dom,盡量最小化dom操作,盡量一次性操作dom,盡量不去查詢dom。
clear?
參考文獻: