vue學(xué)習(xí)筆記

1.vue data屬性里面的getter和setter

data的每個屬性都有兩個相對應(yīng)的get和set屬性。

ES5的對象原型有兩個新的屬性__defineGetter__和__defineSetter__,專門用來給對象綁定get和set??梢赃@樣書寫:


vue雙向綁定原理是由數(shù)據(jù)劫持結(jié)合發(fā)布者-訂閱者模式實現(xiàn)的。

vue的數(shù)據(jù)劫持是通過Object.defineProperty()來對對象的setter和getter屬性進行操作,在數(shù)據(jù)進行變動時,進行你想要的操作。

語法:Object.defineProperty(obj,prop,descriptor)

? ? ? ? ? ? 參數(shù):

? ? ? ? ? ? ? ? obj:要在其上定義屬性的對象。

? ? ? ? ? ? ? ? prop:要定義或修改的屬性名稱。

? ? ? ? ? ? ? ? descriptor:將被定義或修改的屬性描述。

? ? ? ? ? ? 返回值:

? ? ? ? ? ? ? ? ? 被傳遞給函數(shù)的對象。

也就是說他可以控制一個對象屬性的一些特有操作,比如讀寫或是否可枚舉等,這里組要看set和get。

2.vue.js計算屬性computed(getter,setter)

在Vue中,computed的屬性可以被視為是data一樣,可以讀取和設(shè)置,因此在computed中可以分成getter和setter,一般情況下沒有setter,computed預(yù)設(shè)只有g(shù)etter,也就是只能讀取,不能改變設(shè)值。

vue.js計算屬性默認只有g(shù)etter,因為是默認值所以我們也常常忽略不寫,如下代碼:

完整寫法:

計算屬性getter的出發(fā)時間:

如果我們改變上邊代碼里的2個輸入框的值firstName或則lastName,都會觸發(fā)computed以及updated(),也就是說會執(zhí)行:console.log('computed')和console.log('updated');

需要注意的是,不是說我們更改了getter里使用的變量,就會觸發(fā)computed的更新,前提是computed里的值必須要在模板里面使用才行。如果把上面代碼中的p標簽注釋掉,就算改變input的值也不會觸發(fā)computed。

2.vue生命周期。

1new Vue{

?????????router,

?????????store,

? ? ? ? ? //components: { App } vue1.0的寫法

????????????render: h => h(App) vue2.0的寫法

}).$mount('#app')

1.首先需要了解這是 es 6 的語法,表示 Vue 實例選項對象的 render 方法作為一個函數(shù),接受傳入的參數(shù) h 函數(shù),返回 h(App) 的函數(shù)調(diào)用結(jié)果。

2.其次,Vue 在創(chuàng)建 Vue 實例時,通過調(diào)用 render 方法來渲染實例的 DOM 樹。

3.最后,Vue 在調(diào)用 render 方法時,會傳入一個 createElement 函數(shù)作為參數(shù),也就是這里的 h 的實參是 createElement 函數(shù),然后 createElement 會以 APP 為參數(shù)進行調(diào)用,關(guān)于 createElement 函數(shù)的參數(shù)說明參見:Element-Arguments。


先了解一下vue的虛擬dom:

Vitual DOM是一種虛擬dom技術(shù),本質(zhì)上是基于javascript實現(xiàn)的,相對于dom對象,javascript對象更簡單,處理速度更快,dom樹的結(jié)構(gòu),屬性信息都可以很容易的用javascript對象表示:

Virtual DOM并沒有完全實現(xiàn)DOM,最主要還是保留了Element之間的層次關(guān)系和一些基本屬性。你給我一個數(shù)據(jù),我根據(jù)數(shù)據(jù)生成一個全新的Virtual DOM,然后跟我上一次生成的Virtual DOM去diff,然后通過patch方法掛載。

我們可以通過javascript對象表示的樹結(jié)構(gòu)來構(gòu)建真正的DOM樹,當(dāng)數(shù)據(jù)發(fā)聲變化時,可以直接修改這個javascript對象,接著對比修改后的對象,記錄下需要對頁面做的dom操作,然后將其應(yīng)用到真正的DOM樹,實現(xiàn)視圖的更新。

VNode生成最關(guān)鍵點是通過render函數(shù),由2種生成方式,第一種是直接在vue對象的option種添加render字段。第二種是寫一個模板或指定el跟元素,它會首先轉(zhuǎn)換成模板,經(jīng)過html語法解析器生成一個ast抽象語法樹,對語法樹做優(yōu)化,然后把語法樹轉(zhuǎn)換成代碼片段,最后通過代碼片段生成function添加到option的render字段中。

? ? ast語法優(yōu)化過程,主要做了2件事:

? ? ? ? 1.會檢測出靜態(tài)的class名和attributes,這樣它們在初始化渲染后永遠不會再被對比了。

? ? ? ? 2.會檢測出最大的靜態(tài)子樹,并且從渲染函數(shù)中萃取出來。這樣在每次重渲染時,它們會直接重用相同的vnode,同時跳過比對。

creteelment方法的功能是給一個Vnode對象添加若干個Vnode,因為整個Vritual DOM是一種樹狀結(jié)構(gòu),每個節(jié)點都可能會有若干子節(jié)點。然后創(chuàng)建一個Vnode對象,如果是一個reserved tag(html,head等一些合法的html標簽)則會創(chuàng)建普通的DOM Vnode,如果是一個component tag(通過vue注冊的自定義component),則會創(chuàng)建Component Vnode對象,它的VnodeComponentOptions不為null。

function patch(oldVnode, vnode, hydrating, removeOnly, parentElm, refElm){

創(chuàng)建好Vnode,下一步就是要把虛擬dom渲染成真正的dom,是通過patch來實現(xiàn)。patch支持3個參數(shù),其中oldNode是一個真實DOM或則一個Vnode對象,它表示當(dāng)前的VNode,vnode是VNode對象類型,它表示待替換的VNode,hydration是bool類型,它表示是否直接使用服務(wù)器端渲染的DOM元素,下面流程圖表示patch的運行邏輯:

patch運行邏輯看上去比較復(fù)雜,有2個方法createElm和patchVnode是生成dom的關(guān)鍵.

createElm方法會根據(jù)vnode的數(shù)據(jù)結(jié)構(gòu)創(chuàng)建真實的DOM節(jié)點,如果vnode有children,則會遍歷這些子節(jié)點,遞歸調(diào)用createElm方法,InsertedVnodeQueue是記錄子節(jié)點創(chuàng)建順序的隊列,每創(chuàng)建一個DOM元素就會往這個隊列中插入當(dāng)前的VNode,當(dāng)整個VNode對象全部轉(zhuǎn)換成為真實的DOM樹時,會依次調(diào)用這個隊列中的VNode hook的insert方法

1.了解vue的$mount所作的工作大體分為3部:

? ? 1.如果你的option里面沒有render函數(shù),那么,通過complieToFunctions將HTML模板編譯成可以生成VNode的Render函數(shù)。

? ? 2.new一個Watcher實例,觸發(fā)updateComponent方法。

? ? 3.生成vnode,經(jīng)過path,把vnode更新到dom上。

從上面的代碼中可以看到,首先判斷option里面有沒有render函數(shù),沒有的話,進一步判斷有沒有template,沒有的話就用dom元素的outerHTML。得到template以后干了什么呢?如下圖:

我們可以看到,調(diào)用了complieToFunction將template轉(zhuǎn)成render函數(shù)。這里面有兩個過程:

將template解析成ast語法樹。

通過ast語法樹生成render函數(shù)。

下一步就開始mountConmponet了。

從上圖可以看出,程序聲明了一個updateComponent 方法,這個是將要被Watcher實例調(diào)用的更新組件的方法。


vm:當(dāng)前的vm實例。

updateComponent 這個非常重要,用來在后面將vnode更新到dom上。

noop無意義的函數(shù)。

null option選項沒有則為null。

true主要是用來判斷是哪個watcher。因為computed計算屬性和如果你要在options里面配置watch了同樣也是使用了 new Watcher ,加上這個用以區(qū)別這三者。

if(isRenderWatcher) {

?????vm._watcher = this;

}

可以看到,如果聲明這個watcher的上下文是用來渲染視圖的,也就是說在mountComponent這里調(diào)用new Watcher的時候,才會把this賦值給_watcher。然后把 watcher push到 _watchers 里面,目的是等到組件銷毀時順便把watcher也銷毀掉。

接下來,就是賦值給 getter , this.getter = expOrFn 。還記得剛才傳過來的 updateComponent 函數(shù)么,沒錯,就是這個賦值給我 getter 。然后我們就到了:

我們可以看到,首先它執(zhí)行的是 pushTarget(this) ,pushTarget(this) 代碼如下:

也就是說如果當(dāng)前有 Dep.target 的話,就把target放到 targetStack 里面,如果沒有的話,就設(shè)為當(dāng)前的target,也就是這個watcher。 接著,就是執(zhí)行了它的 getter 屬性,也就是剛剛傳入 updateComponent 函數(shù)。


官方vue生命周期圖:

從圖可以看出在vue整個的生命周期中會有很多的鉤子函數(shù),提供給我們在vue生命周期不同的時刻進行操作。沒一個組件或則實例都會經(jīng)歷一個完整的生命周期,總共分為三個階段:初始化、運行中、銷毀。

? ? 1.實例、組件通過new Vue()創(chuàng)建出來之后會初始化事件和生命周期,然后會執(zhí)行beforeCreted鉤子函數(shù),這個時候數(shù)據(jù)還沒有掛載,只是一個空殼,無法訪問到數(shù)據(jù)和真實的dom,一般不做操作。

? ? 2.掛載數(shù)據(jù),綁定事件等等,然后執(zhí)行creted函數(shù),這個時候已經(jīng)可以只用到數(shù)據(jù),也可以更改數(shù)據(jù),在這里更改數(shù)據(jù)不會觸發(fā)updated函數(shù),在這里可以在渲染前倒數(shù)第二次更改數(shù)據(jù)的機會,不會觸發(fā)其它鉤子函數(shù),一般可以在這里做初始數(shù)據(jù)的獲取。

? ? 3.接下來開始找實例或則組建對應(yīng)的模板,編譯模板為虛擬dom放入到render函數(shù)中準備渲染,然后執(zhí)行beforeMount鉤子函數(shù),在這個函數(shù)中虛擬dom已經(jīng)創(chuàng)建完成,馬上就要渲染,在這里可以更改數(shù)據(jù),不會觸發(fā)updated,在這里可以在渲染前最后一次更改數(shù)據(jù)的機會。

? ? 4.接下來開始render,渲染出真實dom,然后執(zhí)行mounted鉤子函數(shù),此時,組件已經(jīng)出現(xiàn)在頁面中,數(shù)據(jù)、真實dom都已經(jīng)處理好了,事件都已經(jīng)掛載好了,可以在這里操作真實dom。

? ? 5.當(dāng)組件或?qū)嵗臄?shù)據(jù)更改之后,會立即執(zhí)行beforeUpdate,然后vue的虛擬dom機制就會重新構(gòu)建虛擬dom樹利用diff算法進行對比后重新渲染。

? ? 6.當(dāng)更新完成后,執(zhí)行updated,數(shù)據(jù)已經(jīng)更改完成,dom也重新render完成,可以操作更新后的虛擬dom。

? ? 7.當(dāng)經(jīng)過某種途徑調(diào)用$destroy方法后,立即執(zhí)行beforeDestroy,一般在這里做一些善后工作,例如清除計時器、清除非指令綁定的事件等等

????8.組件的數(shù)據(jù)綁定、監(jiān)聽...去掉后只剩下dom空殼,這個時候,執(zhí)行destroyed,在這里做善后工作也可以

先列出所有的鉤子函數(shù),再一一詳解:

? ? *beforeCreate

? ? *created

? ? *beforeMount

? ? *mounted

? ? *beforeUpdate

? ? *updated

? ? *beforeDsetroy

? ? *destroyed

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容