MVVM
MVVM是Model-View-ViewModel的縮寫
- Model代表數(shù)據(jù)模型栋荸,可在Model中定義數(shù)據(jù)修改等操作的業(yè)務(wù)邏輯砾跃。
- View代表UI界面組件,負(fù)責(zé)將數(shù)據(jù)模型Model轉(zhuǎn)化為UI進(jìn)行展示钞瀑。
- ViewModel表示監(jiān)聽模型中數(shù)據(jù)的改變并控制視圖的行為铸豁,用于處理用戶交互。簡單來說,ViewModel是一個同步View和Model的對象裕照,用來連接View和Model攒发。
MVVM架構(gòu)中View和Model之間并沒有直接的聯(lián)系,而是通過ViewModel進(jìn)行交互晋南。
Model和ViewModel之間的交互是雙向的晨继,因此View上數(shù)據(jù)的變化會同步到Model中,而Model數(shù)據(jù)的變化也會立即反映到View上搬俊。
ViewModel通過雙向數(shù)據(jù)綁定將View層和Model層連接起來,而View和Model之間的同步工作完全是自動的蜒茄,無需人為干預(yù)唉擂。開發(fā)者只需要關(guān)注業(yè)務(wù)邏輯,無需手動操作DOM檀葛,無需關(guān)注數(shù)據(jù)狀態(tài)的同步問題玩祟,復(fù)雜的數(shù)據(jù)狀態(tài)維護(hù)完全由MVVM來統(tǒng)一管理。
Vue雙向數(shù)據(jù)綁定
Vue最顯著的兩個核心是數(shù)據(jù)驅(qū)動和組件系統(tǒng)
Vue實(shí)現(xiàn)數(shù)據(jù)雙向綁定的原理是Object.defineProperty()
方法屿聋,即采用數(shù)據(jù)劫持并結(jié)合發(fā)布者-訂閱者模式空扎,通過Object.defineProperty()
方法來劫持屬性的setter/getter
。當(dāng)數(shù)據(jù)變動時發(fā)布消息給訂閱者润讥,觸發(fā)對應(yīng)監(jiān)聽回調(diào)转锈。當(dāng)將一個普通的JavaScript對象傳遞給Vue實(shí)例作為data
選項(xiàng)時,Vue會遍歷其屬性楚殿,并使用Object.defineProperty()
方法將他們轉(zhuǎn)換為getter/setter
撮慨。用戶是看不到setter/getter
方法,但在內(nèi)部它們會讓Vue追蹤依賴脆粥,在屬性被訪問和修改時會通知其變化砌溺。
Vue的數(shù)據(jù)雙向綁定會見MVVM作為數(shù)據(jù)綁定的入口,整合Observer变隔、Compile规伐、Watcher三者,通過Observer來監(jiān)聽自己Model數(shù)據(jù)的變化匣缘,通過Compile解析編譯模板指令猖闪,最終利用Watcher搭建起Observer和Compile之間的通信橋梁,以達(dá)到數(shù)據(jù)變化視圖更新孵户,視圖交互變化數(shù)據(jù)模型Model變更的雙向綁定效果萧朝。
Vue生命周期
Vue實(shí)例都具有一個完整的生命周期,從開始創(chuàng)建夏哭、初始化數(shù)據(jù)检柬、編譯模板、掛載DOM、渲染更新渲染何址、卸載等一系列的過程里逆。簡單來說,就是Vue實(shí)例從創(chuàng)建到銷毀的過程用爪。
為什么會存在Vue的生命周期呢原押?Vue生命周期的作用是因?yàn)槠渖芷趦?nèi)存在多個事件鉤子,用以控制整個Vue實(shí)例的過程時更容易形成清晰的邏輯偎血。Vue實(shí)例生命周期中诸衔,提供了一系列事件,使其在事件觸發(fā)時注冊JS方法颇玷,以使用自己注冊的JS方法控制整個大局笨农,在這些事件響應(yīng)方法中this
直接指向的是Vue實(shí)例。
Vue生命周期可分為4大階段8小階段帖渠,分別是
- 創(chuàng)建前后
beforeCreate/created
- 載入前后
beforeMount/mounted
- 更新前后
beforeUpdate/updated
- 銷毀前后
beforeDestroy/destroyed
當(dāng)?shù)谝淮雾撁婕虞d時會觸發(fā)beforeCreate
谒亦、created
、beforeMount
空郊、mounted
鉤子函數(shù)份招,DOM渲染則在mounted
中就已經(jīng)完成了。
Vue實(shí)例生命周期鉤子
每個Vue實(shí)例在被創(chuàng)建時都需經(jīng)過一系列初始化過程狞甚,例如锁摔,設(shè)置數(shù)據(jù)監(jiān)聽、編譯模板入愧、將實(shí)例掛在到DOM并在數(shù)據(jù)變化時更新DOM等鄙漏。同時在此過程中也會運(yùn)行一些稱為生命周期鉤子的函數(shù),以方便用戶在不同階段添加代碼棺蛛。
鉤子 | 描述 |
---|---|
beforeCreate | 組件實(shí)例剛剛被創(chuàng)建怔蚌,組件屬性計(jì)算之前。 |
created | 用來在實(shí)例創(chuàng)建之后執(zhí)行代碼旁赊,組件實(shí)例創(chuàng)建完成桦踊,屬性已綁定,DOOM未生成终畅,$el 屬性不存在籍胯。 |
beforeMount | 模板編譯或掛載之前 |
mounted | 模板編譯或掛載之后,此時并不能保證組件已在document中离福。 |
beforeUpdate | 組件更新之前 |
updated | 組件更新之后 |
beforeDestroy | 組件銷毀前調(diào)用 |
destroyed | 組件銷毀后調(diào)用 |
生命周期鉤子是在Vue對象生命周期的某個階段執(zhí)行的已定義的方法杖狼,從初始化到被銷毀,對象都會遵循不同的生命階段妖爷。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>vue</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<input type="text" v-model="input.msg" ref="msg" />
<button @click="onHandle">更新</button>
</div>
<script>
const vm = new Vue({
//DOM
el:"#app",
//數(shù)據(jù)
data(){
return {
input:{msg:"hello world"}
};
},
//生命周期鉤子函數(shù)
beforeCreate(){
console.log(1, "before create", this.$el, this.input);
},
created(){
console.log(2, "created", this.$el, this.input);
},
beforeMount(){
this.$set(this.input, "msg", "helo");
console.log(3, "before mount", this.$el, this.input);
},
mounted(){
console.log(4, "mounted", this.$el, this.input, this.$refs.msg);
},
beforeUpdate(){
console.log(5, "before update", this.$el, this.input);
},
updated(){
console.log(6, "updated", this.$el, this.input);
},
beforeDestroy(){
console.log(7, "before destroy", this.$el, this.input);
},
destroyed(){
console.log(8, "destroyed", this.$el, this.input);
},
//
methods:{
onHandle(){
this.input.msg = "hi";
}
}
});
</script>
</body>
</html>
Vue內(nèi)置方法屬性和生命周期的運(yùn)行順序
運(yùn)行順序 | 屬性方法 |
---|---|
1 | props |
2 | methods |
3 | data |
4 | computed |
5 | watch |
創(chuàng)建期間的生命周期函數(shù)
創(chuàng)建前beforeCreate
- 組件創(chuàng)建會執(zhí)行生命周期函數(shù)
beforeCreate
蝶涩,可在當(dāng)前生命周期中創(chuàng)建一個Loading,當(dāng)頁面加載完成后再移除Loading。 -
beforeCreate
在當(dāng)前生命周期函數(shù)中是訪問不到其他生命周期函數(shù)以及data屬性的绿聘。
Vue實(shí)例化后會創(chuàng)建一個Vue類的對象用來處理DOM元素嗽上,這個對象的生命周期可以通過beforeCreate
鉤子函數(shù)來訪問。
Vue實(shí)例剛從內(nèi)存中被創(chuàng)建出來熄攘,此時還沒有初始化好data
和methods
屬性兽愤。
在Vue實(shí)例初始化之后,數(shù)據(jù)觀測data observer
和event/watcher
事件配置之前被調(diào)用挪圾。
beforeCreate
實(shí)例創(chuàng)建前會遍歷data
對象下所有屬性并將其轉(zhuǎn)化為setter/getter
浅萧,也就是為其添加一個被觀察者,后續(xù)添加新屬性時視圖不用更新即可使用哲思,后續(xù)添加的屬性并不會放到觀察者對象中惯殊,此時數(shù)據(jù)并沒有和模板建立聯(lián)系,因此不能操作該屬性也殖。如果要在實(shí)例掛在完成后使添加的屬性觸發(fā)視圖的更新,可使用$set
方法务热,$set
方法會向被觀察者對象中新增自定義的屬性忆嗜。
創(chuàng)建后created
- 當(dāng)created生命周期函數(shù)執(zhí)行時會將data和methods身上的屬性和方法添加到vm實(shí)例上
- created執(zhí)行時會遍歷data的屬性并為屬性添加setter和getter方法
- 可以在created生命周期函數(shù)中發(fā)起AJAX數(shù)據(jù)請求
在created
階段,對象及其事件已經(jīng)完全初始化崎岂, created
是訪問此階段并編寫代碼的鉤子捆毫,簡單來說,此階段是具有默認(rèn)特性的對象冲甘。
Vue實(shí)例已經(jīng)創(chuàng)建完成后被調(diào)用绩卤,在這一步Vue實(shí)例已經(jīng)完成配置:數(shù)據(jù)觀測(data observer)、屬性和方法的運(yùn)算(computed
)江醇、watch/event
事件回調(diào)濒憋。然而,掛載階段還沒開始陶夜,$el
屬性目前尚不可見凛驮。
在模板渲染成HTML前調(diào)用,即通常初始化某些屬性值条辟,然后再渲染成視圖黔夭。
Vue實(shí)例已經(jīng)在內(nèi)存中創(chuàng)建完成,此時data
和methods
已經(jīng)創(chuàng)建完成羽嫡,此時還未開始編譯模板本姥。
created
階段Vue實(shí)例已經(jīng)被創(chuàng)建完畢,屬性已經(jīng)綁定杭棵,屬性是可以操作的婚惫。但DOM還不存在,$el
屬性也還不可以操作。此時也可以使用axios請求辰妙,但頁面還未被渲染出來鹰祸,若請求時間過長則會出現(xiàn)長時間的白屏的現(xiàn)象,因此推薦添加Loading界面密浑。
掛載前 beforeMount
- 生命周期函數(shù)
beforeMount
可以對data
中的數(shù)據(jù)做最后修改 - 在
beforeMount
生命周期函數(shù)中添加的屬性沒有setter
和getter
方法蛙婴,若需要則需使用$set
方法。 -
beforeMount
生命周期函數(shù)中模板和數(shù)據(jù)未進(jìn)行結(jié)合
beforeMount
鉤子調(diào)用階段會檢查是否具有模板用于要在DOM中呈現(xiàn)的對象尔破,若沒有模板則將定義元素的外部HTML視為模板街图。
beforeMount
在掛載開始之前被調(diào)用,相關(guān)的render
函數(shù)首次被調(diào)用懒构。beforeMount
階段已經(jīng)完成了模板的編譯但還未掛在到頁面中餐济。
掛載后mounted
- mounted掛載后數(shù)據(jù)和模板會進(jìn)行結(jié)合并生成真正的DOM結(jié)構(gòu)
- mounted函數(shù)中可訪問到真實(shí)的DOM結(jié)構(gòu)
- mounted函數(shù)中可用于插件實(shí)例化
一旦模板準(zhǔn)備就緒,就會將數(shù)據(jù)放入模板并創(chuàng)建可呈現(xiàn)元素胆剧。使用新數(shù)據(jù)填充元素替換DOM元素絮姆。mounted
鉤子表示DOM已準(zhǔn)備就緒并放置到頁面中。
el
被新創(chuàng)建的vm.$el
替換秩霍,并掛載到實(shí)例上去之后調(diào)用該鉤子篙悯。
在模板渲染成HTML后調(diào)用,通常是初始化頁面完成后铃绒,再對HTML的DOM節(jié)點(diǎn)進(jìn)行一些需要的操作鸽照。
mounted
階段此時已經(jīng)將編譯好的模板掛載到了頁面指定的容器中顯示。
運(yùn)行期間的生命周期函數(shù)
更新前beforeUpdate
- beforeUpdate會多次執(zhí)行颠悬,當(dāng)數(shù)據(jù)更新前會執(zhí)行矮燎。
- beforeUpdate更新前數(shù)據(jù)還未和模板結(jié)合,可在此函數(shù)中做更新數(shù)據(jù)的最后修改赔癌。
當(dāng)外部事件或用戶輸入時诞外,beforeUpdate
鉤子在反映原始DOM元素的更改之前被觸發(fā),此階段表示更改已經(jīng)完成灾票,但尚未準(zhǔn)備好更新DOM浅乔。
數(shù)據(jù)更新時調(diào)用,發(fā)生在虛擬DOM重新渲染和打補(bǔ)丁之前铝条【肝可以在狗子中進(jìn)一步地更改狀態(tài),這不會出發(fā)附加的重渲染過程班缰。
狀態(tài)更新之前執(zhí)行beforeUpdate
鉤子函數(shù)贤壁,此時data
中的狀態(tài)值是最新的,但界面上顯示的數(shù)據(jù)還是舊的埠忘,因?yàn)榇藭r還沒有開始重新渲染DOM節(jié)點(diǎn)脾拆。
更新后updated
- updated函數(shù)是更新的數(shù)據(jù)和模板進(jìn)行組合的位置
- 可在updated函數(shù)中獲取到數(shù)據(jù)更新后最新的DOM結(jié)構(gòu)
- 可在updated函數(shù)中做插件的實(shí)例化馒索,但需添加判斷條件否則會非常消耗性能。
updated
鉤子表示在DOM中程序的更改名船,通過實(shí)際更新DOM對象并觸發(fā)updated
方法绰上,屏幕上的變化才得以呈現(xiàn)。
由于數(shù)據(jù)更改導(dǎo)致的虛擬DOM重新渲染和打補(bǔ)丁渠驼,在這之后會調(diào)用該鉤子蜈块。
當(dāng)這個鉤子被調(diào)用時,組件DOM已經(jīng)更新迷扇,所以現(xiàn)在可以執(zhí)行依賴于DOM的操作百揭。然而大多數(shù)情況下,應(yīng)該避免在此期間更改狀態(tài)蜓席,因?yàn)檫@可能會導(dǎo)致更新無限循環(huán)器一。
updated
函數(shù)在Vue實(shí)例更新完畢后調(diào)用,此時data
中的狀態(tài)值和界面上顯示的數(shù)據(jù)都已經(jīng)完成了更新厨内,界面已經(jīng)被重新渲染好了祈秕。
銷毀期間的生命周期函數(shù)
銷毀前beforeDestroy
- beforeDestroy函數(shù)中可訪問到真實(shí)的DOM結(jié)構(gòu),可在當(dāng)前生命周期函數(shù)中做事件的解綁雏胃、監(jiān)聽移除等操作踢步。
當(dāng)Vue對象被破壞并從內(nèi)存中釋放之前beforeDestroy
鉤子被觸發(fā)
Vue實(shí)例銷毀之前調(diào)用,在這一步中Vue實(shí)例仍然完全可用丑掺。
beforeDestroy
鉤子函數(shù)在Vue實(shí)力銷毀之前調(diào)用,此時Vue實(shí)力仍然完全可用述雾。
銷毀后destroyed
- destroyed函數(shù)執(zhí)行時會將vm和模板之間的關(guān)聯(lián)斷開
- destroyed函數(shù)中無法通過
ref
訪問到真實(shí)DOM結(jié)構(gòu)
destroyed
鉤子被成功運(yùn)行銷毀對象上調(diào)用街州,對象停止并從內(nèi)存中刪除。
Vue實(shí)例銷毀后調(diào)用玻孟,調(diào)用后Vue實(shí)例指示的所有東西都會解綁定唆缴,所有的事件監(jiān)聽器會被移除,所有的子實(shí)例也會被銷毀黍翎。該鉤子在服務(wù)器端渲染期間不會被調(diào)用面徽。
destroyed
鉤子函數(shù)在Vue實(shí)例銷毀后調(diào)用,調(diào)用后Vue實(shí)例指向會解除綁定匣掸,所有的事件監(jiān)聽器會被移除趟紊,所有的子實(shí)例也會被銷毀。
created 與 mounted
-
beforeCreated
時el
和data
并未初始化 -
created
階段完成data
數(shù)據(jù)的初始化碰酝,此時el
還不存在霎匈。 -
beforeMount
階段完成了el
和data
的初始化 -
mounted
階段完成掛載。
created
在模板渲染成HTML前調(diào)用送爸,即通常初始化某些屬性值铛嘱,然后再渲染成視圖暖释。
mounted
在模板渲染成HTML后調(diào)用,通常是初始化頁面完成后再對HTML的DOM節(jié)點(diǎn)進(jìn)行一些需要的操作墨吓。
通常created
使用的次數(shù)多球匕,而mounted
通常是在一些插件的使用或組件的使用中進(jìn)行操作。