1.vue data屬性里面的getter和setter
data的每個(gè)屬性都有兩個(gè)相對(duì)應(yīng)的get和set屬性夯巷。
ES5的對(duì)象原型有兩個(gè)新的屬性__defineGetter__和__defineSetter__,專門用來(lái)給對(duì)象綁定get和set哀墓〕貌停可以這樣書寫:
vue雙向綁定原理是由數(shù)據(jù)劫持結(jié)合發(fā)布者-訂閱者模式實(shí)現(xiàn)的。
vue的數(shù)據(jù)劫持是通過(guò)Object.defineProperty()來(lái)對(duì)對(duì)象的setter和getter屬性進(jìn)行操作麸祷,在數(shù)據(jù)進(jìn)行變動(dòng)時(shí)澎怒,進(jìn)行你想要的操作。
語(yǔ)法:Object.defineProperty(obj,prop,descriptor)
? ? ? ? ? ? 參數(shù):
? ? ? ? ? ? ? ? obj:要在其上定義屬性的對(duì)象阶牍。
? ? ? ? ? ? ? ? prop:要定義或修改的屬性名稱。
? ? ? ? ? ? ? ? descriptor:將被定義或修改的屬性描述星瘾。
? ? ? ? ? ? 返回值:
? ? ? ? ? ? ? ? ? 被傳遞給函數(shù)的對(duì)象走孽。
也就是說(shuō)他可以控制一個(gè)對(duì)象屬性的一些特有操作,比如讀寫或是否可枚舉等琳状,這里組要看set和get磕瓷。
2.vue.js計(jì)算屬性computed(getter,setter)
在Vue中,computed的屬性可以被視為是data一樣念逞,可以讀取和設(shè)置困食,因此在computed中可以分成getter和setter,一般情況下沒有setter翎承,computed預(yù)設(shè)只有g(shù)etter硕盹,也就是只能讀取,不能改變?cè)O(shè)值叨咖。
vue.js計(jì)算屬性默認(rèn)只有g(shù)etter瘩例,因?yàn)槭悄J(rèn)值所以我們也常常忽略不寫啊胶,如下代碼:
完整寫法:
計(jì)算屬性getter的出發(fā)時(shí)間:
如果我們改變上邊代碼里的2個(gè)輸入框的值firstName或則lastName,都會(huì)觸發(fā)computed以及updated()垛贤,也就是說(shuō)會(huì)執(zhí)行:console.log('computed')和console.log('updated')焰坪;
需要注意的是,不是說(shuō)我們更改了getter里使用的變量聘惦,就會(huì)觸發(fā)computed的更新某饰,前提是computed里的值必須要在模板里面使用才行。如果把上面代碼中的p標(biāo)簽注釋掉善绎,就算改變input的值也不會(huì)觸發(fā)computed黔漂。
2.vue生命周期。
1new Vue{
?????????router,
?????????store,
? ? ? ? ? //components: { App } vue1.0的寫法
????????????render: h => h(App) vue2.0的寫法
}).$mount('#app')
1.首先需要了解這是 es 6 的語(yǔ)法涂邀,表示 Vue 實(shí)例選項(xiàng)對(duì)象的 render 方法作為一個(gè)函數(shù)瘟仿,接受傳入的參數(shù) h 函數(shù),返回 h(App) 的函數(shù)調(diào)用結(jié)果比勉。
2.其次劳较,Vue 在創(chuàng)建 Vue 實(shí)例時(shí),通過(guò)調(diào)用 render 方法來(lái)渲染實(shí)例的 DOM 樹浩聋。
3.最后观蜗,Vue 在調(diào)用 render 方法時(shí),會(huì)傳入一個(gè) createElement 函數(shù)作為參數(shù)衣洁,也就是這里的 h 的實(shí)參是 createElement 函數(shù)墓捻,然后 createElement 會(huì)以 APP 為參數(shù)進(jìn)行調(diào)用,關(guān)于 createElement 函數(shù)的參數(shù)說(shuō)明參見:Element-Arguments坊夫。
先了解一下vue的虛擬dom:
Vitual DOM是一種虛擬dom技術(shù)砖第,本質(zhì)上是基于javascript實(shí)現(xiàn)的,相對(duì)于dom對(duì)象环凿,javascript對(duì)象更簡(jiǎn)單梧兼,處理速度更快,dom樹的結(jié)構(gòu)智听,屬性信息都可以很容易的用javascript對(duì)象表示:
Virtual DOM并沒有完全實(shí)現(xiàn)DOM羽杰,最主要還是保留了Element之間的層次關(guān)系和一些基本屬性。你給我一個(gè)數(shù)據(jù)到推,我根據(jù)數(shù)據(jù)生成一個(gè)全新的Virtual DOM考赛,然后跟我上一次生成的Virtual DOM去diff,然后通過(guò)patch方法掛載莉测。
我們可以通過(guò)javascript對(duì)象表示的樹結(jié)構(gòu)來(lái)構(gòu)建真正的DOM樹颜骤,當(dāng)數(shù)據(jù)發(fā)聲變化時(shí),可以直接修改這個(gè)javascript對(duì)象悔雹,接著對(duì)比修改后的對(duì)象复哆,記錄下需要對(duì)頁(yè)面做的dom操作欣喧,然后將其應(yīng)用到真正的DOM樹,實(shí)現(xiàn)視圖的更新梯找。
VNode生成最關(guān)鍵點(diǎn)是通過(guò)render函數(shù)唆阿,由2種生成方式,第一種是直接在vue對(duì)象的option種添加render字段锈锤。第二種是寫一個(gè)模板或指定el跟元素驯鳖,它會(huì)首先轉(zhuǎn)換成模板,經(jīng)過(guò)html語(yǔ)法解析器生成一個(gè)ast抽象語(yǔ)法樹久免,對(duì)語(yǔ)法樹做優(yōu)化浅辙,然后把語(yǔ)法樹轉(zhuǎn)換成代碼片段,最后通過(guò)代碼片段生成function添加到option的render字段中阎姥。
? ? ast語(yǔ)法優(yōu)化過(guò)程记舆,主要做了2件事:
? ? ? ? 1.會(huì)檢測(cè)出靜態(tài)的class名和attributes,這樣它們?cè)诔跏蓟秩竞笥肋h(yuǎn)不會(huì)再被對(duì)比了呼巴。
? ? ? ? 2.會(huì)檢測(cè)出最大的靜態(tài)子樹泽腮,并且從渲染函數(shù)中萃取出來(lái)。這樣在每次重渲染時(shí)衣赶,它們會(huì)直接重用相同的vnode诊赊,同時(shí)跳過(guò)比對(duì)。
creteelment方法的功能是給一個(gè)Vnode對(duì)象添加若干個(gè)Vnode府瞄,因?yàn)檎麄€(gè)Vritual DOM是一種樹狀結(jié)構(gòu)碧磅,每個(gè)節(jié)點(diǎn)都可能會(huì)有若干子節(jié)點(diǎn)。然后創(chuàng)建一個(gè)Vnode對(duì)象遵馆,如果是一個(gè)reserved tag(html,head等一些合法的html標(biāo)簽)則會(huì)創(chuàng)建普通的DOM Vnode鲸郊,如果是一個(gè)component tag(通過(guò)vue注冊(cè)的自定義component),則會(huì)創(chuàng)建Component Vnode對(duì)象货邓,它的VnodeComponentOptions不為null严望。
function patch(oldVnode, vnode, hydrating, removeOnly, parentElm, refElm){
創(chuàng)建好Vnode,下一步就是要把虛擬dom渲染成真正的dom逻恐,是通過(guò)patch來(lái)實(shí)現(xiàn)。patch支持3個(gè)參數(shù)峻黍,其中oldNode是一個(gè)真實(shí)DOM或則一個(gè)Vnode對(duì)象复隆,它表示當(dāng)前的VNode,vnode是VNode對(duì)象類型,它表示待替換的VNode,hydration是bool類型姆涩,它表示是否直接使用服務(wù)器端渲染的DOM元素挽拂,下面流程圖表示patch的運(yùn)行邏輯:
patch運(yùn)行邏輯看上去比較復(fù)雜,有2個(gè)方法createElm和patchVnode是生成dom的關(guān)鍵.
createElm方法會(huì)根據(jù)vnode的數(shù)據(jù)結(jié)構(gòu)創(chuàng)建真實(shí)的DOM節(jié)點(diǎn)骨饿,如果vnode有children亏栈,則會(huì)遍歷這些子節(jié)點(diǎn)台腥,遞歸調(diào)用createElm方法,InsertedVnodeQueue是記錄子節(jié)點(diǎn)創(chuàng)建順序的隊(duì)列绒北,每創(chuàng)建一個(gè)DOM元素就會(huì)往這個(gè)隊(duì)列中插入當(dāng)前的VNode,當(dāng)整個(gè)VNode對(duì)象全部轉(zhuǎn)換成為真實(shí)的DOM樹時(shí)黎侈,會(huì)依次調(diào)用這個(gè)隊(duì)列中的VNode hook的insert方法
1.了解vue的$mount所作的工作大體分為3部:
? ? 1.如果你的option里面沒有render函數(shù),那么闷游,通過(guò)complieToFunctions將HTML模板編譯成可以生成VNode的Render函數(shù)峻汉。
? ? 2.new一個(gè)Watcher實(shí)例,觸發(fā)updateComponent方法脐往。
? ? 3.生成vnode休吠,經(jīng)過(guò)path,把vnode更新到dom上业簿。
從上面的代碼中可以看到瘤礁,首先判斷option里面有沒有render函數(shù),沒有的話梅尤,進(jìn)一步判斷有沒有template柜思,沒有的話就用dom元素的outerHTML。得到template以后干了什么呢克饶?如下圖:
我們可以看到酝蜒,調(diào)用了complieToFunction將template轉(zhuǎn)成render函數(shù)。這里面有兩個(gè)過(guò)程:
將template解析成ast語(yǔ)法樹矾湃。
通過(guò)ast語(yǔ)法樹生成render函數(shù)亡脑。
下一步就開始mountConmponet了。
從上圖可以看出邀跃,程序聲明了一個(gè)updateComponent 方法霉咨,這個(gè)是將要被Watcher實(shí)例調(diào)用的更新組件的方法。
vm:當(dāng)前的vm實(shí)例拍屑。
updateComponent 這個(gè)非常重要途戒,用來(lái)在后面將vnode更新到dom上。
noop無(wú)意義的函數(shù)僵驰。
null option選項(xiàng)沒有則為null喷斋。
true主要是用來(lái)判斷是哪個(gè)watcher。因?yàn)閏omputed計(jì)算屬性和如果你要在options里面配置watch了同樣也是使用了 new Watcher 蒜茴,加上這個(gè)用以區(qū)別這三者星爪。
if(isRenderWatcher) {
?????vm._watcher = this;
}
可以看到,如果聲明這個(gè)watcher的上下文是用來(lái)渲染視圖的粉私,也就是說(shuō)在mountComponent這里調(diào)用new Watcher的時(shí)候顽腾,才會(huì)把this賦值給_watcher。然后把 watcher push到 _watchers 里面诺核,目的是等到組件銷毀時(shí)順便把watcher也銷毀掉抄肖。
接下來(lái)久信,就是賦值給 getter , this.getter = expOrFn 。還記得剛才傳過(guò)來(lái)的 updateComponent 函數(shù)么漓摩,沒錯(cuò)裙士,就是這個(gè)賦值給我 getter 。然后我們就到了:
我們可以看到幌甘,首先它執(zhí)行的是 pushTarget(this) ,pushTarget(this) 代碼如下:
也就是說(shuō)如果當(dāng)前有 Dep.target 的話潮售,就把target放到 targetStack 里面,如果沒有的話锅风,就設(shè)為當(dāng)前的target酥诽,也就是這個(gè)watcher。 接著皱埠,就是執(zhí)行了它的 getter 屬性肮帐,也就是剛剛傳入 updateComponent 函數(shù)。
官方vue生命周期圖:
從圖可以看出在vue整個(gè)的生命周期中會(huì)有很多的鉤子函數(shù)边器,提供給我們?cè)趘ue生命周期不同的時(shí)刻進(jìn)行操作训枢。沒一個(gè)組件或則實(shí)例都會(huì)經(jīng)歷一個(gè)完整的生命周期,總共分為三個(gè)階段:初始化忘巧、運(yùn)行中恒界、銷毀。
? ? 1.實(shí)例砚嘴、組件通過(guò)new Vue()創(chuàng)建出來(lái)之后會(huì)初始化事件和生命周期十酣,然后會(huì)執(zhí)行beforeCreted鉤子函數(shù),這個(gè)時(shí)候數(shù)據(jù)還沒有掛載际长,只是一個(gè)空殼耸采,無(wú)法訪問到數(shù)據(jù)和真實(shí)的dom,一般不做操作工育。
? ? 2.掛載數(shù)據(jù)虾宇,綁定事件等等,然后執(zhí)行creted函數(shù)如绸,這個(gè)時(shí)候已經(jīng)可以只用到數(shù)據(jù)嘱朽,也可以更改數(shù)據(jù),在這里更改數(shù)據(jù)不會(huì)觸發(fā)updated函數(shù)怔接,在這里可以在渲染前倒數(shù)第二次更改數(shù)據(jù)的機(jī)會(huì)燥翅,不會(huì)觸發(fā)其它鉤子函數(shù),一般可以在這里做初始數(shù)據(jù)的獲取蜕提。
? ? 3.接下來(lái)開始找實(shí)例或則組建對(duì)應(yīng)的模板,編譯模板為虛擬dom放入到render函數(shù)中準(zhǔn)備渲染靶端,然后執(zhí)行beforeMount鉤子函數(shù)谎势,在這個(gè)函數(shù)中虛擬dom已經(jīng)創(chuàng)建完成凛膏,馬上就要渲染,在這里可以更改數(shù)據(jù)脏榆,不會(huì)觸發(fā)updated猖毫,在這里可以在渲染前最后一次更改數(shù)據(jù)的機(jī)會(huì)。
? ? 4.接下來(lái)開始render须喂,渲染出真實(shí)dom吁断,然后執(zhí)行mounted鉤子函數(shù),此時(shí)坞生,組件已經(jīng)出現(xiàn)在頁(yè)面中仔役,數(shù)據(jù)、真實(shí)dom都已經(jīng)處理好了是己,事件都已經(jīng)掛載好了又兵,可以在這里操作真實(shí)dom。
? ? 5.當(dāng)組件或?qū)嵗臄?shù)據(jù)更改之后卒废,會(huì)立即執(zhí)行beforeUpdate沛厨,然后vue的虛擬dom機(jī)制就會(huì)重新構(gòu)建虛擬dom樹利用diff算法進(jìn)行對(duì)比后重新渲染。
? ? 6.當(dāng)更新完成后摔认,執(zhí)行updated逆皮,數(shù)據(jù)已經(jīng)更改完成,dom也重新render完成参袱,可以操作更新后的虛擬dom电谣。
? ? 7.當(dāng)經(jīng)過(guò)某種途徑調(diào)用$destroy方法后,立即執(zhí)行beforeDestroy蓖柔,一般在這里做一些善后工作辰企,例如清除計(jì)時(shí)器、清除非指令綁定的事件等等
????8.組件的數(shù)據(jù)綁定况鸣、監(jiān)聽...去掉后只剩下dom空殼牢贸,這個(gè)時(shí)候靶草,執(zhí)行destroyed舆蝴,在這里做善后工作也可以
先列出所有的鉤子函數(shù),再一一詳解:
? ? *beforeCreate
? ? *created
? ? *beforeMount
? ? *mounted
? ? *beforeUpdate
? ? *updated
? ? *beforeDsetroy
? ? *destroyed