最常考的 30 個(gè) Vue 面試題總結(jié)?。?!
Vue 常見面試題總結(jié)
MVVM模型?
MVVM,是Model-View-ViewModel的簡(jiǎn)寫,其本質(zhì)是MVC模型的升級(jí)版。其中 Model 代表數(shù)據(jù)模型,View 代表看到的頁(yè)面,ViewModel是View和Model之間的橋梁,數(shù)據(jù)會(huì)綁定到ViewModel層并自動(dòng)將數(shù)據(jù)渲染到頁(yè)面中,視圖變化的時(shí)候會(huì)通知ViewModel層更新數(shù)據(jù)。以前是通過操作DOM來更新視圖,現(xiàn)在是數(shù)據(jù)驅(qū)動(dòng)視圖。
Vue的生命周期
Vue 的生命周期可以分為8個(gè)階段:創(chuàng)建前后、掛載前后、更新前后、銷毀前后,以及一些特殊場(chǎng)景的生命周期。Vue 3 中還新增了是3個(gè)用于調(diào)試和服務(wù)端渲染的場(chǎng)景。
Vue 2中的生命周期鉤子 Vue 3選項(xiàng)式API的生命周期選項(xiàng) Vue 3 組合API中生命周期鉤子 描述
beforeCreate beforeCreate setup() 創(chuàng)建前,此時(shí)data和 methods的數(shù)據(jù)都還沒有初始化
created created setup() 創(chuàng)建后,data中有值,尚未掛載,可以進(jìn)行一些Ajax請(qǐng)求
beforeMount beforeMount onBeforeMount 掛載前,會(huì)找到虛擬DOM,編譯成Render
mounted mounted onMounted 掛載后,DOM已創(chuàng)建,可用于獲取訪問數(shù)據(jù)和DOM元素
beforeUpdate beforeUpdate onBeforeUpdate 更新前,可用于獲取更新前各種狀態(tài)
updated updated onUpdated 更新后,所有狀態(tài)已是最新
beforeDestroy beforeUnmount onBeforeUnmount 銷毀前,可用于一些定時(shí)器或訂閱的取消
destroyed unmounted onUnmounted 銷毀后,可用于一些定時(shí)器或訂閱的取消
activated activated onActivated keep-alive緩存的組件激活時(shí)
deactivated deactivated onDeactivated keep-alive緩存的組件停用時(shí)
errorCaptured errorCaptured onErrorCaptured 捕獲一個(gè)來自子孫組件的錯(cuò)誤時(shí)調(diào)用
— renderTracked onRenderTracked 調(diào)試鉤子,響應(yīng)式依賴被收集時(shí)調(diào)用
— renderTriggered onRenderTriggered 調(diào)試鉤子,響應(yīng)式依賴被觸發(fā)時(shí)調(diào)用
— serverPrefetch onServerPrefetch 組件實(shí)例在服務(wù)器上被渲染前調(diào)用
「父子組件的生命周期:」
加載渲染階段:父 beforeCreate -> 父 created -> 父 beforeMount -> 子 beforeCreate -> 子 created -> 子 beforeMount -> 子 mounted -> 父 mounted
更新階段:父 beforeUpdate -> 子 beforeUpdate -> 子 updated -> 父 updated
銷毀階段:父 beforeDestroy -> 子 beforeDestroy -> 子 destroyed -> 父 destroyed
Vue.$nextTick
「在下次 DOM 更新循環(huán)結(jié)束之后執(zhí)行延遲回調(diào)。在修改數(shù)據(jù)之后立即使用這個(gè)方法,獲取更新后的 DOM。」
nextTick 是 Vue 提供的一個(gè)全局 API,由于 Vue 的異步更新策略,導(dǎo)致我們對(duì)數(shù)據(jù)修改后不會(huì)直接體現(xiàn)在 DOM 上,此時(shí)如果想要立即獲取更新后的 DOM 狀態(tài),就需要借助該方法。
Vue 在更新 DOM 時(shí)是異步執(zhí)行的。當(dāng)數(shù)據(jù)發(fā)生變化,Vue 將開啟一個(gè)異步更新隊(duì)列,并緩沖在同一事件循環(huán)中發(fā)生的所有數(shù)據(jù)變更。如果同一個(gè) watcher 被多次觸發(fā),只會(huì)被推入隊(duì)列一次。這種在緩沖時(shí)去除重復(fù)數(shù)據(jù)對(duì)于避免不必要的計(jì)算和 DOM 操作是非常重要的。nextTick方法會(huì)在隊(duì)列中加入一個(gè)回調(diào)函數(shù),確保該函數(shù)在前面的 DOM 操作完成后才調(diào)用。
使用場(chǎng)景:
如果想要在修改數(shù)據(jù)后立刻得到更新后的DOM結(jié)構(gòu),可以使用Vue.nextTick()
在created生命周期中進(jìn)行DOM操作
Vue 實(shí)例掛載過程中發(fā)生了什么?
掛載過程指的是 app.mount()過程,這是一個(gè)初始化過程,整體上做了兩件事情:初始化和建立更新機(jī)制。
初始化會(huì)創(chuàng)建組件實(shí)例、初始化組件狀態(tài)、創(chuàng)建各種響應(yīng)式數(shù)據(jù)。
建立更新機(jī)制這一步會(huì)立即執(zhí)行一次組件的更新函數(shù),這會(huì)首次執(zhí)行組件渲染函數(shù)并執(zhí)行patch將vnode 轉(zhuǎn)換為 dom;同時(shí)首次執(zhí)行渲染函數(shù)會(huì)創(chuàng)建它內(nèi)部響應(yīng)式數(shù)據(jù)和組件更新函數(shù)之間的依賴關(guān)系,這使得以后數(shù)據(jù)發(fā)生變化時(shí)會(huì)執(zhí)行對(duì)應(yīng)的更新函數(shù)。
Vue 的模版編譯原理
Vue 中有個(gè)獨(dú)特的編譯器模塊,稱為compiler,它的主要作用是將用戶編寫的template編譯為js中可執(zhí)行的render函數(shù)。
在Vue 中,編譯器會(huì)先對(duì)template進(jìn)行解析,這一步稱為parse,結(jié)束之后得到一個(gè)JS對(duì)象,稱之為抽象語(yǔ)法樹AST;然后是對(duì)AST進(jìn)行深加工的轉(zhuǎn)換過程,這一步稱為transform,最后將前面得到的AST生成JS代碼,也就是render函數(shù)。
Vue 的響應(yīng)式原理
Vue 2 中的數(shù)據(jù)響應(yīng)式會(huì)根據(jù)數(shù)據(jù)類型做不同的處理。如果是對(duì)象,則通過Object.defineProperty(obj,key,descriptor)攔截對(duì)象屬性訪問,當(dāng)數(shù)據(jù)被訪問或改變時(shí),感知并作出反應(yīng);如果是數(shù)組,則通過覆蓋數(shù)組原型的方法,擴(kuò)展它的7個(gè)變更方法(push、pop、shift、unshift、splice、sort、reverse),使這些方法可以額外的做更新通知,從而做出響應(yīng)。
缺點(diǎn):
初始化時(shí)的遞歸遍歷會(huì)造成性能損失;
通知更新過程需要維護(hù)大量 dep 實(shí)例和 watcher 實(shí)例,額外占用內(nèi)存較多;
新增或刪除對(duì)象屬性無法攔截,需要通過 Vue.set 及 delete 這樣的 API 才能生效;
對(duì)于ES6中新產(chǎn)生的Map、Set這些數(shù)據(jù)結(jié)構(gòu)不支持。
Vue 3 中利用ES6的Proxy機(jī)制代理需要響應(yīng)化的數(shù)據(jù)??梢酝瑫r(shí)支持對(duì)象和數(shù)組,動(dòng)態(tài)屬性增、刪都可以攔截,新增數(shù)據(jù)結(jié)構(gòu)均支持,對(duì)象嵌套屬性運(yùn)行時(shí)遞歸,用到時(shí)才代理,也不需要維護(hù)特別多的依賴關(guān)系,性能取得很大進(jìn)步。
虛擬DOM
概念:
虛擬DOM,顧名思義就是虛擬的DOM對(duì)象,它本身就是一個(gè)JS對(duì)象,只不過是通過不同的屬性去描述一個(gè)視圖結(jié)構(gòu)。
虛擬DOM的好處:
(1) 性能提升
直接操作DOM是有限制的,一個(gè)真實(shí)元素上有很多屬性,如果直接對(duì)其進(jìn)行操作,同時(shí)會(huì)對(duì)很多額外的屬性內(nèi)容進(jìn)行了操作,這是沒有必要的。如果將這些操作轉(zhuǎn)移到JS對(duì)象上,就會(huì)簡(jiǎn)單很多。另外,操作DOM的代價(jià)是比較昂貴的,頻繁的操作DOM容易引起頁(yè)面的重繪和回流。如果通過抽象VNode進(jìn)行中間處理,可以有效減少直接操作DOM次數(shù),從而減少頁(yè)面的重繪和回流。
(2) 方便跨平臺(tái)實(shí)現(xiàn)
同一VNode節(jié)點(diǎn)可以渲染成不同平臺(tái)上對(duì)應(yīng)的內(nèi)容,比如:渲染在瀏覽器是DOM元素節(jié)點(diǎn),渲染在Native(iOS、Android)變?yōu)閷?duì)應(yīng)的控件。Vue 3 中允許開發(fā)者基于VNode實(shí)現(xiàn)自定義渲染器(renderer),以便于針對(duì)不同平臺(tái)進(jìn)行渲染。
結(jié)構(gòu):
沒有統(tǒng)一的標(biāo)準(zhǔn),一般包括tag、props、children三項(xiàng)。
tag:必選。就是標(biāo)簽,也可以是組件,或者函數(shù)。
props:非必選。就是這個(gè)標(biāo)簽上的屬性和方法。
children:非必選。就是這個(gè)標(biāo)簽的內(nèi)容或者子節(jié)點(diǎn)。如果是文本節(jié)點(diǎn)就是字符串;如果有子節(jié)點(diǎn)就是數(shù)組。換句話說,如果判斷children是字符串的話,就表示一定是文本節(jié)點(diǎn),這個(gè)節(jié)點(diǎn)肯定沒有子元素。
diff 算法
概念:
diff算法是一種對(duì)比算法,通過對(duì)比舊的虛擬DOM和新的虛擬DOM,得出是哪個(gè)虛擬節(jié)點(diǎn)發(fā)生了改變,找出這個(gè)虛擬節(jié)點(diǎn)并只更新這個(gè)虛擬節(jié)點(diǎn)所對(duì)應(yīng)的真實(shí)節(jié)點(diǎn),而不用更新其他未發(fā)生改變的節(jié)點(diǎn),實(shí)現(xiàn)精準(zhǔn)地更新真實(shí)DOM,進(jìn)而提高效率。
對(duì)比方式:
diff算法的整體策略是:深度優(yōu)先,同層比較。比較只會(huì)在同層級(jí)進(jìn)行, 不會(huì)跨層級(jí)比較;比較的過程中,循環(huán)從兩邊向中間收攏。
首先判斷兩個(gè)節(jié)點(diǎn)的tag是否相同,不同則刪除該節(jié)點(diǎn)重新創(chuàng)建節(jié)點(diǎn)進(jìn)行替換。
tag相同時(shí),先替換屬性,然后對(duì)比子元素,分為以下幾種情況:
新舊節(jié)點(diǎn)都有子元素時(shí),采用雙指針方式進(jìn)行對(duì)比。新舊頭尾指針進(jìn)行比較,循環(huán)向中間靠攏,根據(jù)情況調(diào)用patchVnode進(jìn)行patch重復(fù)流程、調(diào)用createElem創(chuàng)建一個(gè)新節(jié)點(diǎn),從哈希表尋找 key一致的VNode節(jié)點(diǎn)再分情況操作。
新節(jié)點(diǎn)有子元素,舊節(jié)點(diǎn)沒有子元素,則將子元素虛擬節(jié)點(diǎn)轉(zhuǎn)化成真實(shí)節(jié)點(diǎn)插入即可。
新節(jié)點(diǎn)沒有子元素,舊節(jié)點(diǎn)有子元素,則清空子元素,并設(shè)置為新節(jié)點(diǎn)的文本內(nèi)容。
新舊節(jié)點(diǎn)都沒有子元素時(shí),即都為文本節(jié)點(diǎn),則直接對(duì)比文本內(nèi)容,不同則更新。
Vue中key的作用?
key的作用主要是為了更加高效的更新虛擬 DOM。
Vue 判斷兩個(gè)節(jié)點(diǎn)是否相同時(shí),主要是判斷兩者的key和元素類型tag。因此,如果不設(shè)置key ,它的值就是 undefined,則可能永遠(yuǎn)認(rèn)為這是兩個(gè)相同的節(jié)點(diǎn),只能去做更新操作,將造成大量的 DOM 更新操作。
為什么組件中的 data 是一個(gè)函數(shù)?
在 new Vue() 中,可以是函數(shù)也可以是對(duì)象,因?yàn)楦鶎?shí)例只有一個(gè),不會(huì)產(chǎn)生數(shù)據(jù)污染。
在組件中,data 必須為函數(shù),目的是為了防止多個(gè)組件實(shí)例對(duì)象之間共用一個(gè) data,產(chǎn)生數(shù)據(jù)污染;而采用函數(shù)的形式,initData 時(shí)會(huì)將其作為工廠函數(shù)都會(huì)返回全新的 data 對(duì)象。
Vue 中組件間的通信方式?
父子組件通信:父向子傳遞數(shù)據(jù)是通過props,子向父是通過$emit觸發(fā)事件;通過父鏈/子鏈也可以通信($parent/$children);ref也可以訪問組件實(shí)例;provide/inject;$attrs/$listeners。
兄弟組件通信:全局事件總線EventBus、Vuex。
跨層級(jí)組件通信:全局事件總線EventBus、Vuex、provide/inject。
v-show 和 v-if 的區(qū)別?
控制手段不同。v-show是通過給元素添加 css 屬性display: none,但元素仍然存在;而v-if控制元素顯示或隱藏是將元素整個(gè)添加或刪除。
編譯過程不同。v-if切換有一個(gè)局部編譯/卸載的過程,切換過程中合適的銷毀和重建內(nèi)部的事件監(jiān)聽和子組件;v-show只是簡(jiǎn)單的基于 css 切換。
編譯條件不同。v-if是真正的條件渲染,它會(huì)確保在切換過程中條件塊內(nèi)的事件監(jiān)聽器和子組件適當(dāng)?shù)乇讳N毀和重建,渲染條件為假時(shí),并不做操作,直到為真才渲染。
觸發(fā)生命周期不同。v-show由 false 變?yōu)?true 的時(shí)候不會(huì)觸發(fā)組件的生命周期;v-if由 false 變?yōu)?true 的時(shí)候,觸發(fā)組件的beforeCreate、created、beforeMount、mounted鉤子,由 true 變?yōu)?false 的時(shí)候觸發(fā)組件的beforeDestory、destoryed鉤子。
性能消耗不同。v-if有更高的切換消耗;v-show有更高的初始渲染消耗。
使用場(chǎng)景:
如果需要非常頻繁地切換,則使用v-show較好,如:手風(fēng)琴菜單,tab 頁(yè)簽等;如果在運(yùn)行時(shí)條件很少改變,則使用v-if較好,如:用戶登錄之后,根據(jù)權(quán)限不同來顯示不同的內(nèi)容。
computed 和 watch 的區(qū)別?
computed計(jì)算屬性,依賴其它屬性計(jì)算值,內(nèi)部任一依賴項(xiàng)的變化都會(huì)重新執(zhí)行該函數(shù),計(jì)算屬性有緩存,多次重復(fù)使用計(jì)算屬性時(shí)會(huì)從緩存中獲取返回值,計(jì)算屬性必須要有return關(guān)鍵詞。
watch偵聽到某一數(shù)據(jù)的變化從而觸發(fā)函數(shù)。當(dāng)數(shù)據(jù)為對(duì)象類型時(shí),對(duì)象中的屬性值變化時(shí)需要使用深度偵聽deep屬性,也可在頁(yè)面第一次加載時(shí)使用立即偵聽immdiate屬性。
運(yùn)用場(chǎng)景:
計(jì)算屬性一般用在模板渲染中,某個(gè)值是依賴其它響應(yīng)對(duì)象甚至是計(jì)算屬性而來;而偵聽屬性適用于觀測(cè)某個(gè)值的變化去完成一段復(fù)雜的業(yè)務(wù)邏輯。
v-if 和 v-for 為什么不建議放在一起使用?
Vue 2 中,v-for的優(yōu)先級(jí)比v-if高,這意味著v-if將分別重復(fù)運(yùn)行于每一個(gè)v-for循環(huán)中。如果要遍歷的數(shù)組很大,而真正要展示的數(shù)據(jù)很少時(shí),將造成很大的性能浪費(fèi)。
Vue 3 中,則完全相反,v-if的優(yōu)先級(jí)高于v-for,所以v-if執(zhí)行時(shí),它調(diào)用的變量還不存在,會(huì)導(dǎo)致異常。
通常有兩種情況導(dǎo)致要這樣做:
為了過濾列表中的項(xiàng)目,比如:v-for = "user in users" v-if = "user.active"。這種情況,可以定義一個(gè)計(jì)算屬性,讓其返回過濾后的列表即可。
為了避免渲染本該被隱藏的列表,比如v-for = "user in users" v-if = "showUsersFlag"。這種情況,可以將v-if移至容器元素上或在外面包一層template即可。
Vue 2中的set方法?
set是Vue 2中的一個(gè)全局API。可手動(dòng)添加響應(yīng)式數(shù)據(jù),解決數(shù)據(jù)變化視圖未更新問題。當(dāng)在項(xiàng)目中直接設(shè)置數(shù)組的某一項(xiàng)的值,或者直接設(shè)置對(duì)象的某個(gè)屬性值,會(huì)發(fā)現(xiàn)頁(yè)面并沒有更新。這是因?yàn)镺bject.defineProperty()的限制,監(jiān)聽不到數(shù)據(jù)變化,可通過this.$set(數(shù)組或?qū)ο螅瑪?shù)組下標(biāo)或?qū)ο蟮膶傩悦?,更新后的?解決。
keep-alive 是什么?
作用:實(shí)現(xiàn)組件緩存,保持組件的狀態(tài),避免反復(fù)渲染導(dǎo)致的性能問題。
工作原理:Vue.js 內(nèi)部將 DOM 節(jié)點(diǎn),抽象成了一個(gè)個(gè)的 VNode 節(jié)點(diǎn),keep-alive組件的緩存也是基于 VNode 節(jié)點(diǎn)的。它將滿足條件的組件在 cache 對(duì)象中緩存起來,重新渲染的時(shí)候再將 VNode 節(jié)點(diǎn)從 cache 對(duì)象中取出并渲染。
可以設(shè)置以下屬性:
① include:字符串或正則,只有名稱匹配的組件會(huì)被緩存。
② exclude:字符串或正則,任何名稱匹配的組件都不會(huì)被緩存。
③ max:數(shù)字,最多可以緩存多少組件實(shí)例。
匹配首先檢查組件的name選項(xiàng),如果name選項(xiàng)不可用,則匹配它的局部注冊(cè)名稱(父組件 components選項(xiàng)的鍵值),匿名組件不能被匹配。
設(shè)置了keep-alive緩存的組件,會(huì)多出兩個(gè)生命周期鉤子:activated、deactivated。
首次進(jìn)入組件時(shí):beforeCreate --> created --> beforeMount --> mounted --> activated --> beforeUpdate --> updated --> deactivated
再次進(jìn)入組件時(shí):activated --> beforeUpdate --> updated --> deactivated
mixin
mixin(混入), 它提供了一種非常靈活的方式,來分發(fā) Vue 組件中的可復(fù)用功能。
使用場(chǎng)景:不同組件中經(jīng)常會(huì)用到一些相同或相似的代碼,這些代碼的功能相對(duì)獨(dú)立??梢酝ㄟ^mixin 將相同或相似的代碼提出來。
缺點(diǎn):
變量來源不明確
多 mixin 可能會(huì)造成命名沖突(解決方式:Vue 3的組合API)
mixin 和組件出現(xiàn)多對(duì)多的關(guān)系,使項(xiàng)目復(fù)雜度變高。
插槽
slot插槽,一般在組件內(nèi)部使用,封裝組件時(shí),在組件內(nèi)部不確定該位置是以何種形式的元素展示時(shí),可以通過slot占據(jù)這個(gè)位置,該位置的元素需要父組件以內(nèi)容形式傳遞過來。slot分為:
默認(rèn)插槽:子組件用<slot>標(biāo)簽來確定渲染的位置,標(biāo)簽里面可以放DOM結(jié)構(gòu)作為后備內(nèi)容,當(dāng)父組件在使用的時(shí)候,可以直接在子組件的標(biāo)簽內(nèi)寫入內(nèi)容,該部分內(nèi)容將插入子組件的<slot>標(biāo)簽位置。如果父組件使用的時(shí)候沒有往插槽傳入內(nèi)容,后備內(nèi)容就會(huì)顯示在頁(yè)面。
具名插槽:子組件用name屬性來表示插槽的名字,沒有指定name的插槽,會(huì)有隱含的名稱叫做 default。父組件中在使用時(shí)在默認(rèn)插槽的基礎(chǔ)上通過v-slot指令指定元素需要放在哪個(gè)插槽中,v-slot值為子組件插槽name屬性值。使用v-slot指令指定元素放在哪個(gè)插槽中,必須配合<template>元素,且一個(gè)<template>元素只能對(duì)應(yīng)一個(gè)預(yù)留的插槽,即不能多個(gè)<template> 元素都使用v-slot指令指定相同的插槽。v-slot的簡(jiǎn)寫是#,例如v-slot:header可以簡(jiǎn)寫為#header。
作用域插槽:子組件在<slot>標(biāo)簽上綁定props數(shù)據(jù),以將子組件數(shù)據(jù)傳給父組件使用。父組件獲取插槽綁定 props 數(shù)據(jù)的方法:
scope="接收的變量名":<template scope="接收的變量名">
slot-scope="接收的變量名":<template slot-scope="接收的變量名">
v-slot:插槽名="接收的變量名":<template v-slot:插槽名="接收的變量名">
Vue 中的修飾符有哪些?
在Vue 中,修飾符處理了許多 DOM 事件的細(xì)節(jié),讓我們不再需要花大量的時(shí)間去處理這些煩惱的事情,而能有更多的精力專注于程序的邏輯處理。Vue中修飾符分為以下幾種:
表單修飾符
lazy 填完信息,光標(biāo)離開標(biāo)簽的時(shí)候,才會(huì)將值賦予給value,也就是在change事件之后再進(jìn)行信息同步。
number 自動(dòng)將用戶輸入值轉(zhuǎn)化為數(shù)值類型,但如果這個(gè)值無法被parseFloat解析,則會(huì)返回原來的值。
trim 自動(dòng)過濾用戶輸入的首尾空格,而中間的空格不會(huì)被過濾。
事件修飾符
stop 阻止了事件冒泡,相當(dāng)于調(diào)用了event.stopPropagation方法。
prevent 阻止了事件的默認(rèn)行為,相當(dāng)于調(diào)用了event.preventDefault方法。
self 只當(dāng)在 event.target 是當(dāng)前元素自身時(shí)觸發(fā)處理函數(shù)。
once 綁定了事件以后只能觸發(fā)一次,第二次就不會(huì)觸發(fā)。
capture 使用事件捕獲模式,即元素自身觸發(fā)的事件先在此處處理,然后才交由內(nèi)部元素進(jìn)行處理。
passive 告訴瀏覽器你不想阻止事件的默認(rèn)行為。
native 讓組件變成像html內(nèi)置標(biāo)簽?zāi)菢颖O(jiān)聽根元素的原生事件,否則組件上使用 v-on 只會(huì)監(jiān)聽自定義事件。
鼠標(biāo)按鍵修飾符
left 左鍵點(diǎn)擊。
right 右鍵點(diǎn)擊。
middle 中鍵點(diǎn)擊。
鍵值修飾符
鍵盤修飾符是用來修飾鍵盤事件(onkeyup,onkeydown)的,有如下:keyCode存在很多,但vue為我們提供了別名,分為以下兩種:
普通鍵(enter、tab、delete、space、esc、up...)
系統(tǒng)修飾鍵(ctrl、alt、meta、shift...)
對(duì) SPA 的理解?
概念:
SPA(Single-page application),即單頁(yè)面應(yīng)用,它是一種網(wǎng)絡(luò)應(yīng)用程序或網(wǎng)站的模型,通過動(dòng)態(tài)重寫當(dāng)前頁(yè)面來與用戶交互,這種方法避免了頁(yè)面之間切換時(shí)打斷用戶體驗(yàn)。在SPA中,所有必要的代碼(HTML、JavaScript 和 CSS)都通過單個(gè)頁(yè)面的加載而檢索,或者根據(jù)需要(通常是響應(yīng)用戶操作)動(dòng)態(tài)裝載適當(dāng)?shù)馁Y源并添加到頁(yè)面。頁(yè)面在任何時(shí)間點(diǎn)都不會(huì)重新加載,也不會(huì)將控制轉(zhuǎn)移到其他頁(yè)面。舉個(gè)例子,就像一個(gè)杯子,上午裝的是牛奶,中午裝的是咖啡,下午裝的是茶,變得始終是內(nèi)容,杯子始終不變。
SPA與MPA的區(qū)別:
MPA(Muti-page application),即多頁(yè)面應(yīng)用。在MPA中,每個(gè)頁(yè)面都是一個(gè)主頁(yè)面,都是獨(dú)立的,每當(dāng)訪問一個(gè)頁(yè)面時(shí),都需要重新加載 Html、CSS、JS 文件,公共文件則根據(jù)需求按需加載。
SPAMPA組成一個(gè)主頁(yè)面和多個(gè)頁(yè)面片段多個(gè)主頁(yè)面url模式hash模式history模式SEO搜索引擎優(yōu)化難實(shí)現(xiàn),可使用SSR方式改善容易實(shí)現(xiàn)數(shù)據(jù)傳遞容易通過url、cookie、localStorage等傳遞頁(yè)面切換速度快,用戶體驗(yàn)良好切換加載資源,速度慢,用戶體驗(yàn)差維護(hù)成本相對(duì)容易相對(duì)復(fù)雜
3.SPA的優(yōu)缺點(diǎn):
缺點(diǎn):
不利于搜索引擎的抓取
首次渲染速度相對(duì)較慢
優(yōu)點(diǎn):
具有桌面應(yīng)用的即時(shí)性、網(wǎng)站的可移植性和可訪問性
用戶體驗(yàn)好、快,內(nèi)容的改變不需要重新加載整個(gè)頁(yè)面
良好的前后端分離,分工更明確
雙向綁定?
概念:
Vue 中雙向綁定是一個(gè)指令v-model,可以綁定一個(gè)響應(yīng)式數(shù)據(jù)到視圖,同時(shí)視圖的變化能改變?cè)撝?。v-model是語(yǔ)法糖,默認(rèn)情況下相當(dāng)于:value和@input,使用v-model可以減少大量繁瑣的事件處理代碼,提高開發(fā)效率。
使用:
通常在表單項(xiàng)上使用v-model,還可以在自定義組件上使用,表示某個(gè)值的輸入和輸出控制。
原理:
v-model是一個(gè)指令,雙向綁定實(shí)際上是Vue 的編譯器完成的,通過輸出包含v-model模版的組件渲染函數(shù),實(shí)際上還是value屬性的綁定及input事件監(jiān)聽,事件回調(diào)函數(shù)中會(huì)做相應(yīng)變量的更新操作。
子組件是否可以直接改變父組件的數(shù)據(jù)?
所有的prop都遵循著單項(xiàng)綁定原則,props因父組件的更新而變化,自然地將新狀態(tài)向下流往子組件,而不會(huì)逆向傳遞。這避免了子組件意外修改父組件的狀態(tài)的情況,不然應(yīng)用的數(shù)據(jù)流將很容易變得混亂而難以理解。
另外,每次父組件更新后,所有的子組件中的props都會(huì)被更新為最新值,這就意味著不應(yīng)該子組件中去修改一個(gè)prop,若這么做了,Vue 會(huì)在控制臺(tái)上拋出警告。
實(shí)際開發(fā)過程中通常有兩個(gè)場(chǎng)景導(dǎo)致要修改prop:
prop被用于傳入初始值,而子組件想在之后將其作為一個(gè)局部數(shù)據(jù)屬性。這種情況下,最好是新定義一個(gè)局部數(shù)據(jù)屬性,從props獲取初始值即可。
需要對(duì)傳入的prop值做進(jìn)一步轉(zhuǎn)換。最好是基于該prop值定義一個(gè)計(jì)算屬性。
實(shí)踐中,如果確實(shí)要更改父組件屬性,應(yīng)emit一個(gè)事件讓父組件變更。當(dāng)對(duì)象或數(shù)組作為props被傳入時(shí),雖然子組件無法更改props綁定,但仍然「可以」更改對(duì)象或數(shù)組內(nèi)部的值。這是因?yàn)镴S的對(duì)象和數(shù)組是按引用傳遞,而對(duì)于 Vue 來說,禁止這樣的改動(dòng)雖然可能,但是有很大的性能損耗,比較得不償失。
Vue Router中的常用路由模式和原理?
hash 模式:
location.hash的值就是url中 # 后面的東西。它的特點(diǎn)在于:hash雖然出現(xiàn)url中,但不會(huì)被包含在HTTP請(qǐng)求中,對(duì)后端完全沒有影響,因此改變hash不會(huì)重新加載頁(yè)面。
可以為hash的改變添加監(jiān)聽事件window.addEventListener("hashchange", funcRef, false),每一次改變hash (window.location.hash),都會(huì)在瀏覽器的訪問歷史中增加一個(gè)記錄,利用hash的以上特點(diǎn),就可以實(shí)現(xiàn)「前端路由更新視圖但不重新請(qǐng)求頁(yè)面」的功能了。
特點(diǎn):兼容性好但是不美觀
history 模式:
利用 HTML5 History Interface 中新增的pushState()和replaceState()方法。
這兩個(gè)方法應(yīng)用于瀏覽器的歷史記錄棧,在當(dāng)前已有的back、forward、go 的基礎(chǔ)上,他們提供了對(duì)歷史記錄進(jìn)行修改的功能。
這兩個(gè)方法有個(gè)共同點(diǎn):當(dāng)調(diào)用他們修改瀏覽器歷史記錄棧后,雖然當(dāng)前url改變了,但瀏覽器不會(huì)刷新頁(yè)面,這就為單頁(yè)面應(yīng)用前端路由“更新視圖但不重新請(qǐng)求頁(yè)面”提供了基礎(chǔ)
特點(diǎn):雖然美觀,但是刷新會(huì)出現(xiàn) 404 需要后端進(jìn)行配置。
動(dòng)態(tài)路由?
很多時(shí)候,我們需要將給定匹配模式的路由映射到同一個(gè)組件,這種情況就需要定義動(dòng)態(tài)路由。例如,我們有一個(gè) User組件,對(duì)于所有 ID 各不相同的用戶,都要使用這個(gè)組件來渲染。那么,我們可以在 vue-router 的路由路徑中使用動(dòng)態(tài)路徑參數(shù)(dynamic segment)來達(dá)到這個(gè)效果:{path: '/user/:id', compenent: User},其中:id就是動(dòng)態(tài)路徑參數(shù)。
對(duì)Vuex的理解?
概念:
Vuex 是 Vue 專用的狀態(tài)管理庫(kù),它以全局方式集中管理應(yīng)用的狀態(tài),并以相應(yīng)的規(guī)則保證狀態(tài)以一種可預(yù)測(cè)的方式發(fā)生變化。
解決的問題:
Vuex 主要解決的問題是多組件之間狀態(tài)共享。利用各種通信方式,雖然也能夠?qū)崿F(xiàn)狀態(tài)共享,但是往往需要在多個(gè)組件之間保持狀態(tài)的一致性,這種模式很容易出問題,也會(huì)使程序邏輯變得復(fù)雜。Vuex 通過把組件的共享狀態(tài)抽取出來,以全局單例模式管理,這樣任何組件都能用一致的方式獲取和修改狀態(tài),響應(yīng)式的數(shù)據(jù)也能夠保證簡(jiǎn)潔的單向流動(dòng),使代碼變得更具結(jié)構(gòu)化且易于維護(hù)。
什么時(shí)候用:
Vuex 并非是必須的,它能夠管理狀態(tài),但同時(shí)也帶來更多的概念和框架。如果我們不打算開發(fā)大型單頁(yè)應(yīng)用或應(yīng)用里沒有大量全局的狀態(tài)需要維護(hù),完全沒有使用Vuex的必要,一個(gè)簡(jiǎn)單的 store 模式就夠了。反之,Vuex將是自然而然的選擇。
用法:
Vuex 將全局狀態(tài)放入state對(duì)象中,它本身是一顆狀態(tài)樹,組件中使用store實(shí)例的state訪問這些狀態(tài);然后用配套的mutation方法修改這些狀態(tài),并且只能用mutation修改狀態(tài),在組件中調(diào)用commit方法提交mutation;如果應(yīng)用中有異步操作或復(fù)雜邏輯組合,需要編寫action,執(zhí)行結(jié)束如果有狀態(tài)修改仍需提交mutation,組件中通過dispatch派發(fā)action。最后是模塊化,通過modules選項(xiàng)組織拆分出去的各個(gè)子模塊,在訪問狀態(tài)(state)時(shí)需注意添加子模塊的名稱,如果子模塊有設(shè)置namespace,那么提交mutation和派發(fā)action時(shí)還需要額外的命名空間前綴。
頁(yè)面刷新后Vuex 狀態(tài)丟失怎么解決?
Vuex 只是在內(nèi)存中保存狀態(tài),刷新后就會(huì)丟失,如果要持久化就需要保存起來。
localStorage就很合適,提交mutation的時(shí)候同時(shí)存入localStorage,在store中把值取出來作為state的初始值即可。
也可以使用第三方插件,推薦使用vuex-persist插件,它是為 Vuex 持久化儲(chǔ)存而生的一個(gè)插件,不需要你手動(dòng)存取storage,而是直接將狀態(tài)保存至 cookie 或者 localStorage中。
關(guān)于 Vue SSR 的理解?
SSR即服務(wù)端渲染(Server Side Render),就是將 Vue 在客戶端把標(biāo)簽渲染成 html 的工作放在服務(wù)端完成,然后再把 html 直接返回給客戶端。
優(yōu)點(diǎn):
有著更好的 SEO,并且首屏加載速度更快。
缺點(diǎn):
開發(fā)條件會(huì)受限制,服務(wù)器端渲染只支持 beforeCreate 和 created 兩個(gè)鉤子,當(dāng)我們需要一些外部擴(kuò)展庫(kù)時(shí)需要特殊處理,服務(wù)端渲染應(yīng)用程序也需要處于 Node.js 的運(yùn)行環(huán)境。服務(wù)器會(huì)有更大的負(fù)載需求。
了解哪些 Vue 的性能優(yōu)化方法?
路由懶加載。有效拆分應(yīng)用大小,訪問時(shí)才異步加載。
keep-alive緩存頁(yè)面。避免重復(fù)創(chuàng)建組件實(shí)例,且能保留緩存組件狀態(tài)。
v-for遍歷避免同時(shí)使用v-if。實(shí)際上在 Vue 3 中已經(jīng)是一個(gè)錯(cuò)誤用法了。
長(zhǎng)列表性能優(yōu)化,可采用虛擬列表。
v-once。不再變化的數(shù)據(jù)使用v-once。
事件銷毀。組件銷毀后把全局變量和定時(shí)器銷毀。
圖片懶加載。
第三方插件按需引入。
子組件分割。較重的狀態(tài)組件適合拆分。
服務(wù)端渲染。
作者:前端開發(fā)愛好者
歡迎關(guān)注微信公眾號(hào) :前端開發(fā)愛好者
添加好友備注【進(jìn)階學(xué)習(xí)】拉你進(jìn)技術(shù)交流群