這次跟大家分享一些關於Vue的常見面試題,帶你梳理基礎知識,增強Vue知識儲備,值得收藏,快來看看吧!
MVVM,是Model-View-ViewModel
的簡寫,其本質是MVC
模型的升級版。其中Model
代表資料模型,View
代表看到的頁面,ViewModel
是View
和Model
之間的橋樑,資料會綁定到ViewModel
層並自動將資料渲染到頁面中,視圖變化的時候會通知ViewModel
層更新資料。以前是透過操作DOM
來更新視圖,現在是資料驅動視圖
。
每個Vue 元件實例在建立後都會經過一系列的初始化過程,這個過程中會執行叫做生命週期鉤子的函數,以便於使用者在特定的階段有機會新增自己的程式碼。
Vue 的生命週期可以分為8個階段:創建前後、掛載前後、更新前後、銷毀前後,以及一些特殊場景的生命週期。 Vue 3 中也新增了是3個用於偵錯和服務端渲染的場景。 【相關推薦:vuejs影片教學、web前端開發】
Vue 2中的生命週期 | Vue 3中的生命週期 | 描述 |
---|---|---|
#beforeCreate |
beforeCreate |
在建立前,此時data 和methods 的資料都還沒有初始化 |
created |
created |
建立後,data 中有值,尚未掛載,可以進行一些Ajax 請求 |
beforeMount |
#beforeMount |
掛載前,會找到虛擬DOM ,編譯成Render
|
mounted |
mounted |
mounted
|
#掛載後, | DOM已創建,可用於取得存取資料和DOM 元素 |
|
#beforeUpdate |
更新前,可用來取得更新前各種狀態 |
|
updated |
更新後,所有狀態已是最新 |
|
|
|
|
|
|
|
在銷毀前,可用來一些計時器或訂閱的取消 |
##destroyed |
unmounted |
|
activated
|
activated |
keep-alive | 快取的元件啟動時
| ##deactivated|
keep-alive 快取的元件停用時 |
||
|
父子元件的生命週期:
載入渲染階段
:父beforeCreate -> 父created -> 父beforeMount - > 子beforeCreate -> 子created -> 子beforeMount -> 子mounted -> 父mounted更新階段
:父beforeUpdate -> 子beforeUpdate -> 子updated -> 父updated銷毀階段
:父beforeDestroy -> 子beforeDestroy -> 子destroyed ->父destroyed
Vue.$nextTick
在下次DOM 更新迴圈結束後執行延遲回呼。在修改資料之後立即使用這個方法,以取得更新後的 DOM。
nextTick
是Vue 提供的一個全域API,由於Vue 的非同步更新策略,導致我們對資料修改後不會直接體現在DOM 上,此時如果想要立即取得更新後的DOM 狀態,就需要藉助此方法。 Vue 在更新 DOM 時是非同步執行的。當資料發生變化,Vue 將開啟一個非同步更新佇列,並緩衝在同一事件循環中發生的所有資料變更。如果同一個
watcher
被多次觸發,只會被推入隊列一次。這種在緩衝時去除重複資料對於避免不必要的計算和 DOM 操作是非常重要的。 nextTick
方法會在佇列中加入一個回呼函數,確保函數在前面的 DOM 操作完成後才呼叫。 使用場景:
##Vue 實例掛載過程中發生了什麼事? 掛載過程指的是
app.mount()過程,這是一個初始化過程,整體上做了兩件事:
初始化。
初始化會建立元件實例、初始化元件狀態、建立各種響應式資料。
建立更新機制這一步驟會立即執行一次元件的更新函數,這會首次執行元件渲染函數並執行
patch; 同時首次執行渲染函數會建立它內部響應式資料和元件更新函數之間的依賴關係,這使得以後資料變更時會執行對應的更新函數。 Vue 的模版編譯原理
template
進行解析,這一步稱為
虛擬DOM的好處:
(1) 效能提升
直接操作DOM是有限制的,一個真實元素上有很多屬性,如果直接對其進行操作,同時會對很多額外的屬性內容進行了操作,這是不必要的。如果將這些操作轉移到JS物件上,就會簡單很多。另外,操作DOM的代價是比較昂貴的,頻繁的操作DOM容易造成頁面的重繪和回流。如果透過抽象VNode進行中間處理,可以有效減少直接操作DOM次數,進而減少頁面的重繪和回流。
(2) 方便跨平台實作
同一VNode節點可以渲染成不同平台上對應的內容,例如:渲染在瀏覽器是DOM元素節點,渲染在Native(iOS、Android)變成對應的控制項。 Vue 3 中允許開發者基於VNode實作自訂渲染器(renderer),以便於針對不同平台進行渲染。
結構:
沒有統一的標準,一般包括tag
、props
、children
三項。 tag
:必選。就是標籤,也可以是組件,或是函數。 props
:非必選。就是這個標籤上的屬性和方法。 children
:非必選。就是這個標籤的內容或子節點。如果是文字節點就是字串;如果有子節點就是數組。換句話說,如果判斷children
是字串的話,就表示一定是文字節點,這個節點一定沒有子元素。
#1、概念:
diff
演算法是一種對比演算法,透過比較舊的虛擬DOM和新的虛擬DOM,得出是哪個虛擬節點發生了改變,找出這個虛擬節點並只更新這個虛擬節點所對應的真實節點,而不用更新其他未發生改變的節點,實現精準地更新真實DOM,進而提高效率。
2、比較方式:
diff
演算法的整體策略是:深度優先,同層比較
。比較只會在同層級進行, 不會跨層級比較;比較的過程中,循環從兩邊向中間收攏。
tag
是否相同,不同則刪除該節點重新建立節點進行替換。 tag
相同時,先取代屬性,再對比子元素,分為下列幾種情況:patchVnode
進行patch
重複流程、呼叫createElem
建立一個新節點,從雜湊表尋找key
一致的VNode
節點再分狀況運算。 key
的作用主要是為了更有效率的更新虛擬 DOM
。
Vue 判斷兩個節點是否相同時,主要是判斷兩者的key
和元素類型tag
。因此,如果不設定key
,它的值就是 undefined,則可能永遠認為這是兩個相同的節點,只能去做更新操作,將造成大量的 DOM 更新操作。
在 new Vue() 中,可以是函數也可以是對象,因為根實例只有一個,不會產生資料污染。
在元件中,data 必須為函數,目的是為了防止多個元件實例物件之間共用一個data,產生資料污染;而採用函數的形式,initData 時會將其作為工廠函數都會傳回全新的data 物件。
父子元件通訊:
父傳遞資料是透過props
,子向父是透過$emit
觸發事件;透過父鏈/子鏈也可以通訊($parent
/$children
);ref
也可以存取元件實例;provide
/inject
;$attrs
/$listeners
。
兄弟元件通訊:
全域事件匯流排EventBus
、Vuex
。
跨層級元件通訊:
全域事件匯流排EventBus
、Vuex
、provide
/ inject
。
控製手段不同。 v-show
是透過為元素添加css 屬性display: none
,但元素仍然存在;而v-if
控制元素顯示或隱藏是將元素整個新增或刪除。
編譯過程不同。 v-if
切換有一個局部編譯/卸載的過程,切換過程中適當的銷毀和重建內部的事件監聽和子元件;v-show
只是簡單的基於 css 切換。
編譯條件不同。 v-if
是真正的條件渲染,它會確保在切換過程中條件區塊內的事件監聽器和子元件適當地被銷毀和重建,渲染條件為假時,並不做操作,直到為真才渲染。
觸發生命週期不同。 v-show
由false 變成true 的時候不會觸發元件的生命週期;v-if
由false 變成true 的時候,觸發元件的beforeCreate
、created
、beforeMount
、mounted
鉤子,由true 變成false 的時候觸發元件的beforeDestory
、destoryed
鉤子。
效能消耗不同。 v-if
有較高的切換消耗;v-show
有較高的初始渲染消耗。
使用場景:
如果需要非常頻繁地切換,則使用v-show
較好,如:手風琴選單,tab 頁籤等;
如果在執行時間條件很少改變,則使用v-if
較好,如:使用者登入之後,根據權限不同來顯示不同的內容。
computed
計算屬性,依賴其它屬性計算值,內部任一依賴項的變化都會重新執行該函數,計算屬性有緩存,多次重複使用計算屬性時會從快取中取得回傳值,而計算屬性必須要有return
關鍵字。 watch
偵聽某一資料的變化從而觸發函數。當資料為物件類型時,物件中的屬性值變更時需要使用深度偵聽deep
屬性,也可在頁面第一次載入時使用立即偵聽immdiate
屬性。 運用場景:
計算屬性一般用在範本渲染中,某個值是依賴其它回應物件甚至是計算屬性而來;而偵測屬性適用於觀測某個值的變化去完成一段複雜的業務邏輯。
Vue 2 中,v-for
的優先權比v-if
高,這表示v-if
將分別重複運行於每一個v-for
循環。如果要遍歷的陣列很大,而真正要展示的資料很少時,將造成很大的效能浪費。
Vue 3 中,則完全相反,v-if
的優先權高於v-for
,所以v-if
執行時,它所呼叫的變數還不存在,會導致異常。
通常有兩種情況導致要這樣做:
v-for = "user in users" v-if = "user.active"
。這種情況,可以定義一個計算屬性,讓其傳回過濾後的清單即可。 v-for = "user in users" v-if = "showUsersFlag"
。這種情況,可以將v-if
移至容器元素上或在外麵包一層template
即可。 可手動新增響應式數據,解決資料變更檢視未更新問題。當在專案中直接設定數組的某一項的值,或是直接設定物件的某個屬性值,會發現頁面並沒有更新。這是因為Object.defineProperty()
的限制,監聽不到資料變化,可透過this.$set(數組或對象,數組下標或對象的屬性名,更新後的值)
解決。
keep-alive
元件的快取也是基於 VNode 節點的。它將滿足條件的元件在 cache 物件中快取起來,重新渲染的時候再將 VNode 節點從 cache 物件中取出並渲染。 include
:字串或正規則,只有名稱符合的元件會被快取。 exclude
:字串或正規則,任何名稱符合的元件都不會被快取。 max
:數字,最多可以快取多少元件實例。 name
選項,如果name
選項不可用,則符合它的局部註冊名稱(父元件components選項的鍵值),匿名元件不能被匹配。 設定了keep-alive
快取的元件,會多出兩個生命週期鉤子:activated
、deactivated
。
第一次進入元件時:beforeCreate --> created --> beforeMount --> mounted --> activated --> beforeUpdate --> updated --> deactivated
再次進入元件時:activated --> beforeUpdate --> updated --> deactivated
mixin(混入), 它提供了一種非常靈活的方式,來分發Vue 元件中的可重複使用功能。
slot插槽,一般在元件內部使用,封裝元件時,元件內部不在確定該位置是以何種形式的元素展示時,可以透過
slot佔據這個位置,該位置的元素需要父元件以內容形式傳遞過來。
slot分為:
:子元件用
標籤來決定渲染的位置,標籤裡面可以放
DOM結構作為後備內容,當父元件在使用的時候,可以直接在子元件的標籤內寫入內容,該部分內容將插入子元件的
標籤位置。如果父元件使用的時候沒有往插槽傳入內容,後備內容就會顯示在頁面。
:子元件用
name屬性來表示插槽的名字,沒有指定
name的插槽,會有隱含的名稱叫做
default。父元件中在使用時在預設插槽的基礎上透過
v-slot指令指定元素需要放在哪個插槽中,
v-slot值為子元件插槽
name屬性值。使用
v-slot指令指定元素放在哪個插槽中,必須配合
元素,且一個
元素只能對應一個預留的插槽,即不能多個
元素都使用
v-slot指令指定相同的插槽。
v-slot的簡寫是
#,例如
v-slot:header可以簡寫為
#header。
:子元件在
標籤上綁定
props數據,以將子元件資料傳遞給父組件使用。父元件取得插槽綁定props 資料的方法:
表單修飾符lazy
填完訊息,遊標離開標籤的時候,才會將值賦予給value,也就是在change
事件之後再進行資訊同步。 number
會自動將使用者輸入值轉換為數值類型,但如果這個值無法被parseFloat
解析,則會傳回原來的值。 trim
自動過濾使用者輸入的首尾空格,而中間的空格不會被過濾。
事件修飾符stop
阻止了事件冒泡,相當於呼叫了event.stopPropagation
方法。 prevent
阻止了事件的預設行為,相當於呼叫了event.preventDefault
方法。 self
只有在 event.target
是當前元素本身時觸發處理函數。 once
綁定了事件以後只能觸發一次,第二次就不會觸發。 capture
使用事件擷取模式,也就是元素本身觸發的事件先在此處處理,然後再交由內部元素處理。 passive
告訴瀏覽器你不想阻止事件的預設行為。 native
讓元件變成像html
內建標籤一樣監聽根元素的原生事件,否則元件上使用 v-on
只會監聽自訂事件。
滑鼠按鍵修飾符號left
左鍵點擊。 right
右鍵點選。 middle
中鍵點選。
鍵值修飾符
鍵盤修飾符是用來修飾鍵盤事件(onkeyup
,onkeydown
)的,有如下:keyCode
存在很多,但vue
為我們提供了別名,分為以下兩種:
概念:SPA(Single-page application)
,即單一頁面應用,它是網路應用程式或網站的模型,透過動態重寫當前頁面來與用戶交互,這種方法避免了頁面之間切換時打斷用戶體驗。在SPA
中,所有必要的程式碼(HTML、JavaScript 和 CSS)都透過單一頁面的載入而檢索,或根據需要(通常是回應使用者操作)動態載入適當的資源並新增到頁面。頁面在任何時間點都不會重新加載,也不會將控制權轉移到其他頁面。舉個例子,就像一個杯子,早上裝的是牛奶,中午裝的是咖啡,下午裝的是茶,變得始終是內容,杯子始終不變。
SPA
與MPA
的差異:MPA(Muti-page application)
,即多頁面應用。在MPA
中,每個頁面都是一個主頁面,都是獨立的,每當訪問一個頁面時,都需要重新加載Html、CSS、JS 文件,公共文件則根據需求按需加載。
SPA | MPA | |
---|---|---|
組成 | 一個主頁面和多個頁面片段 | 多個主頁 |
#url模式 | hash模式 | history模式 |
SEO搜尋引擎最佳化 | 難實現,可使用SSR方式改善 | 容易實現 |
資料傳遞 | 容易 | 透過url、cookie、localStorage等傳遞 |
頁面切換 | 速度快,使用者體驗良好 | 切換載入資源,速度慢,使用者體驗差 |
#維護成本 | #相對容易 | #相對複雜 |
SPA
的優缺點:
優點:
缺點:
概念:
Vue 中雙向綁定是指令v-model
,可以綁定一個響應式資料到視圖,同時視圖的變化能改變該值。 v-model
是語法糖,預設相當於:value
和@input
,使用v-model
可以減少大量繁瑣的事件處理程式碼,提高開發效率。
使用:
通常在表單項目上使用v-model
,也可以在自訂元件上使用,表示某個值的輸入和輸出控制。
原理:v-model
是一個指令,雙向綁定其實是Vue 的編譯器完成的,透過輸出包含v -model
模版的元件渲染函數,實際上還是value
屬性的綁定及input
事件監聽,事件回呼函數中會做對應變數的更新操作。
所有的prop
都遵循單一項目綁定原則,props
因父元件的更新而變化,自然地將新狀態向下流往子組件,而不會逆向傳遞。這避免了子元件意外修改父元件的狀態的情況,不然應用的資料流將很容易變得混亂而難以理解。
另外,每次父元件更新後,所有的子元件中的props
都會更新為最新值,這就表示不應該子元件中去修改一個prop
,若這麼做了,Vue 會在控制台上拋出警告。
實際開發過程中通常有兩個場景導致要修改prop
:
prop
被使用於傳入初始值,而子元件想在之後將其作為局部資料屬性。在這種情況下,最好是新定義一個局部資料屬性,從props
取得初始值即可。 prop
值做進一步轉換。最好是基於該prop
值定義一個計算屬性。 實作中,如果確實要變更父元件屬性,應emit
一個事件讓父元件變更。當物件或陣列作為props
被傳入時,雖然子元件無法更改props
綁定,但仍然可以更改物件或陣列內部的值。這是因為JS的物件和陣列是按引用傳遞,而對於 Vue 來說,禁止這樣的改動雖然可能,但是有很大的效能損耗,比較得不償失。
1、hash 模式:
location.hash
的值就是url中 # 後面的東西。它的特點在於:hash雖然出現url中,但不會被包含在HTTP請求中,對後端完全沒有影響,因此改變hash不會重新載入頁面。 window.addEventListener("hashchange", funcRef, false)
,每一次改變hash (window.location.hash)
,都會在瀏覽器的訪問歷史中增加一個記錄,利用hash的以上特點,就可以實現前端路由更新視圖但不重新請求頁面的功能了。 2、history 模式:
利用HTML5 History Interface 中新增的pushState()
和replaceState()
方法。
這兩個方法應用於瀏覽器的歷史記錄棧,在目前已有的back
、forward
、go
的基礎上,他們提供了對歷史記錄進行修改的功能。
這兩個方法有個共同點:當呼叫他們修改瀏覽器歷史記錄堆疊後,雖然當前url改變了,但瀏覽器不會刷新頁面,這就為單頁面應用前端路由「更新視圖但不重新請求頁面」提供了基礎
特點:雖然美觀,但是刷新會出現404 需要後端進行設定。
很多時候,我們需要將給定匹配模式的路由對應到同一個元件,這種情況就需要定義動態路由。例如,我們有一個 User元件,對於所有 ID 各不相同的用戶,都要使用這個元件來渲染。那麼,我們可以在vue-router 的路由路徑中使用動態路徑參數(dynamic segment)
來達到這個效果:{path: '/user/:id', compenent: User}
,其中:id
就是動態路徑參數。
概念:
Vuex 是Vue 專用的狀態管理庫,它以全域方式集中管理應用程式的狀態,並以相應的規則保證狀態以一種可預測的方式改變。
解決的問題:
Vuex 主要解決的問題是多元件之間狀態共用。利用各種通訊方式,雖然也能夠實現狀態共享,但是往往需要在多個元件之間保持狀態的一致性,這種模式很容易出問題,也會使程式邏輯變得複雜。 Vuex 透過把元件的共享狀態抽取出來,以全域單例模式管理,讓任何元件都能以一致的方式取得和修改狀態,響應式的資料也能保證簡潔的單向流動,讓程式碼更具結構化且易於維護。
什麼時候用:
Vuex 不是必須的,它能夠管理狀態,但同時也帶來更多的概念和框架。如果我們不打算開發大型單頁應用程式或應用程式裡沒有大量全域的狀態需要維護,完全沒有使用Vuex的必要,一個簡單的 store 模式就夠了。反之,Vuex將是自然的選擇。
用法:
Vuex 將全域狀態放入state
物件中,它本身就是一顆狀態樹,元件中使用store
實例的state
存取這些狀態;然後用配套的mutation
方法修改這些狀態,並且只能用mutation
修改狀態,在元件中呼叫commit
方法提交mutation
;如果應用程式中有非同步操作或複雜邏輯組合,需要編寫action
,執行結束如果有狀態修改仍需提交mutation
,元件中透過dispatch
派發action
。最後是模組化,透過modules
選項組織拆分出去的各個子模組,在存取狀態(state)時需注意新增子模組的名稱,如果子模組有設定namespace
,那麼提交mutation
和派發action
時還需要額外的命名空間前綴。
Vuex 只是在記憶體中儲存狀態,刷新後就會遺失,如果要持久化就需要儲存起來。
localStorage
就很合適,提交mutation
的時候同時存入localStorage
,在store
中把值取出來作為state
的初始值即可。
也可以使用第三方插件,建議使用vuex-persist
插件,它是為Vuex 持久化儲存而生的插件,不需要你手動訪問storage
,而是直接將狀態儲存到cookie
或localStorage
中。
SSR
即服務端渲染(Server Side Render)
,就是將Vue 在客戶端把標籤渲染成html 的工作放在服務端完成,然後再把html 直接回傳給客戶端。
keep-alive
快取頁面。避免重複建立元件實例,且能保留快取組件狀態。 v-for
遍歷避免同時使用v-if
。實際上在 Vue 3 中已經是一個錯誤用法了。 v-once
。不再變化的資料使用v-once
。 以上是【整理分享】一些常見Vue面試題(附答案解析)的詳細內容。更多資訊請關注PHP中文網其他相關文章!