您好,登錄后才能下訂單哦!
本文小編為大家詳細介紹“Vue有哪些高頻面試題”,內容詳細,步驟清晰,細節處理妥當,希望這篇“Vue有哪些高頻面試題”文章能幫助大家解決疑惑,下面跟著小編的思路慢慢深入,一起來學習新知識吧。
這個問題一般問的不多,但是如果問到了你就必須得答出來
回答
Vue2(選項式API) | Vue3(setup) | 描述 |
---|---|---|
beforeCreate | - | 實例創建前 |
created | - | 實例創建后 |
beforeMount | onBeforeMount | DOM掛載前調用 |
mounted | onMounted | DOM掛載完成調用 |
beforeUpdate | onBeforeUpdate | 數據更新之前被調用 |
updated | onUpdated | 數據更新之后被調用 |
beforeDestroy | onBeforeUnmount | 組件銷毀前調用 |
destroyed | onUnmounted | 組件銷毀完成調用 |
這個相對于上一個問題稍微復雜一點,可以試著理解記憶或者直接記住吧
渲染過程
父beforeCreate
父created
父beforeMount
子beforeCreate
子created
子beforeMount
子mounted
父mounted
更新過程
父beforeUpdate
子beforeUpdate
子updated
父updated
銷毀過程
父beforeDestroy
子beforeDestroy
子destroyed
父destroyed
注意如果子組件是異步組件的話它們的執行順序會發生改變,會先執行完父組件的生命周期然后再執行子組件的生命周期
這個問題算是非常基本的題了,它也很好理解,面試一般會問這兩個指令的區別是什么,以及在什么場景下分別用哪個指令合適回答
v-if
表示一個dom元素是否被創建,而v-show
則是控制這個dom元素的display
屬性是否為none
一般在頻繁切換狀態的地方使用v-show
,v-if
則更適合條件不經常改變的場景,因為它切換開銷相對較大
這個問題被問到的頻率還是比較高的,雖然它在實際開發中并不會這么用。
回答
開發過程中一般不建議同時將v-for和v-if放在一個標簽中使用
Vue2中v-for的優先級會更高,所以會先執行循環,再進行v-if判斷,所以這樣就會導致無論需不需展示這個元素,都會先遍歷整個列表
在Vue3中v-if的優先級會更高,但是當我們遍歷一個數組的時候,根據數組中的某個元素進行v-if判斷的時候就會報錯,因為v-if會先執行此時還沒有拿到這個數組。所以Vue3中依然不建議這樣使用
computed和watch實際工作中用的比較多,所以問的也比較多,一般理解了基本都能回答上來
computed是計算屬性,當一個屬性受一個或者多個屬性影響的時候可以使用.watch是偵聽器,當我們需要根據一個屬性的變化而做出一些處理的時候,可以使用watch來對這個屬性進行監聽
computed具有緩存的特點,即當它所依賴的屬性發生改變的時候它才會重新執行內部邏輯.如下代碼
<template>
<div>{{ addSum }}</div>
<div>{{ addSum }}</div>
<div>{{ addSum }}</div>
</template>
<script setup>
import { computed, ref, watch } from "vue";
const a = ref(1)
const b = ref(2)
let addSum = computed(() => {
console.log('內部邏輯執行')
return a.value + b.value
})
</script>
頁面多次使用addSum
,但是只會打印一次"內部邏輯執行"
watch在頁面首次加載的時候默認不會執行,需要設置immediate:true
首次才會執行監聽
watch默認只監聽一層數據,不監聽多層數據里屬性的變化,需要設置deep:true
才會進行深度監聽
關于vue-router
能問的問題非常多,比如它的實現原理,路由跳轉,路由守衛等等,所以建議去系統的查看vue-router
文檔
問題1:vue-router是什么,描述一下它的原理?
Vue Router是Vue官方的路由管理器,有hash和history兩種模式
hash
模式是通過監聽hashchange
事件來實現更新頁面部分內容的操作,url后面會帶有#
號
history
模式則是通過監聽popstate
事件來實現更新頁面部分內容的操作原理和hash
模式差不多,只不過url后面不會出現#
會顯得更加美觀。同時會帶來一個問題,因為沒有#
號,所以當用戶刷新頁面時會向服務器發請求導致請求資源為404,因此需要對nginx
進行一個配置,需要把所有路由都重定向到根頁面
問題2:路由跳轉方式有哪些?
內置組件跳轉
router.push({ path: '/home' })
,router.replace({ path: '/home' })
問題3:說一下路由守衛?
路由守衛分為全局路由守衛,路由獨享守衛,組件路由守衛
全局路由守衛
beforeEach
,接收to、from、next
三個參數,每個路由跳轉前都會觸發,登錄驗證時用的比較多
beforeResolve
,和beforeEach
類似,區別是在導航被確認之前,同時在所有組件內守衛和異步路由組件被解析之后調用
afterEach,在路由跳轉完成后調用,接收to、from兩個參數
路由獨享守衛
beforeEnter
,一般配置在路由配置文件中(router/index.js),對進入某個路由之前進行相關操作
組件路由守衛
接收
to、from、next
三個參數
beforeRouteEnter
,進入該組件之前調用,無法獲取到vue實例
beforeRouteUpdate
,在當前路由改變,但是該組件被復用時調用
beforeRouteLeave
, 在離開當前組件時調用
當面試問你會用vue3嗎,如果你回答會用的話,那么大概率會問vue2和vue3有哪些區別,最近我去面試的時候百分之90都問了這個問題。
回答
寫法上的區別:vue2使用的是options(選項)Api
,vue3的是composition Api
(當然vue3也兼容composition api
)。options Api
中methods,compute,data
等api都是分散的。而composition api
中的代碼是根據邏輯功能來組織的,我們可以將一個功能所定義的methods,compute,data
等api會放在一起,讓我們可以更靈活地組合組件邏輯。
vue2將響應式數據放到data函數中,而vue3則是使用ref
和reactive
將數據聲明為響應式
響應式實現方式:vue2中是通過Object.defineProperty
對數據劫持實現的,vue3中則是使用Proxy
對數據代理實現的。
生命周期區別:vue3中將beforeCreate
和created
合并到了setup
函數中
根節點: vue3組件允許多個根節點,而vue2只允許一個
內置組件: vue3新增了傳送組件Teleport
和異步依賴處理組件Suspense
面試一般會問你如何寫一個vue插件,所以沒寫過vue插件的最好去親自體驗一下
回答:
vue
實例會有一個use
函數,它接受的是一個帶有install
函數的對象和一個可選的選項對象,當我們使用 vue.use(plugin)
或者app.use(plugin)
會調用我們插件的install
屬性的函數,并且將當前組件的實例傳進來.所以在插件中就可以對這個實例進行一些操作來實現我們插件的功能
插槽slot
可以理解為占坑,當使用一個組件的時候,在組件標簽里的對應的內容就會替換掉這個組件中的slot
標簽。
插槽分為默認插槽
,具名插槽
,作用域插槽
。
默認插槽子組件中用slot
標簽來確定渲染位置,父組件使用它時直接在子組件的標簽內寫入內容即可
//子組件
<template>
<slot />
</template>
//父組件
<Child>
<div>默認插槽</div>
</Child>
具名插槽
顧名思義就是具有名字的插槽,子組件中可以用name
熟悉對slot
命名,父組件在使用的時候通過template
中的v-slot:name
或者#name
來定義這個插槽中的內容
//子組件
<template>
<slot name="content"></slot>
</template>
//父組件
<Child>
<template v-slot:content>具名插槽內容</template>
</Child>
作用域插槽
子組件中的slot
可以通過類似組件屬性傳遞的方式將子組件的值傳遞給父組件中這個子組件的插槽內容中
(子組件標簽內),在父組件使用子組件的時候要用v-slot
的值進行接收這些參數,默認插槽可以將其直接寫在子組件標簽上,具名插槽則寫在template
上。而傳過來的值只能在子組件標簽中或者template
標簽中使用。所以在父組件作用域中獲取到了子組件作用域中的變量,可以認為作用域插槽延伸了子組件數據的作用范圍,因此叫做作用域插槽
如果你想詳細理解插槽的作用可以閱讀這篇文章Vue3中插槽(slot)用法匯總 - 掘金 (juejin.cn)
這里我大概歸納了一下vue2和vue3的傳參方式
方式 | Vue2 | Vue3 |
---|---|---|
父傳子 | props | props |
子傳父 | $emit | emits |
父傳子 | $attrs | attrs |
子傳父 | $listeners | 無(合并到 attrs方式) |
父傳子 | provide/inject | provide/inject |
子組件訪問父組件 | $parent | 無 |
父組件訪問子組件 | $children | 無 |
父組件訪問子組件 | $ref | expose&ref |
兄弟組件傳值 | EventBus | mitt |
它們的具體用法可以參考我的這篇文章盤點Vue2和Vue3的10種組件通信方式(值得收藏) - 掘金 (juejin.cn)
除了上面的傳參方式你也可以回答Vuex和Pinia,前提你了解這兩個狀態管理器,因為你說了大概率下個問題就會問你Vuex和Pinia
面試問到這個問題的時候,不要上來就開始說什么state
,mutation
...。你要先闡述Vuex干嘛用的,什么時候需要用Vuex。
回答
Vuex是Vue中的全局狀態管理框架,它可以管理應用的所有組件的狀態。并不是每個項目都需要引入Vuex的,當我們的項目有很多個頁面,并且這些頁面共享著多個數據狀態,此時我們可以引入Vuex。
Vuex有三個核心的概念,state
,mutations
,actions
,其中state
為存放數據的地方,mutations
中的函數作用則是用來修改state
,actions
中一般是用了處理一些異步操作的函數。
Vuex除了上面三個概念還有getters
,moudles
,getters
就像Vue中的計算屬性computed
一樣用來描述依賴響應式狀態state中的復雜邏輯。moudles
則是可以將store分割成模塊(module),每個模塊都擁有自己的state
,mutations
,actions
等,在大型應用中經常用到
場景:當我們異步獲取結果并賦值給state的時候,比如數據請求,我們可以在actions
中進行數據請求,拿到結果通過它的dispatch
方法調用mutations
中修改state
的函數,從而將結果賦值給了state
這個現在問的好像不多,從我最近面試來看只有我提到了才會問一下,但是以后問的肯定會越來越多。關于pinia問的一般是它和Vuex的區別,確切的說應該是它和Vuex4之間的區別
回答
pinia
其實就是Vuex5,它和Vuex的主要區別有以下幾點
Pinia使用更簡單,更符合開發者的開發習慣
pinia
中沒有了mutations
,狀態state
的修改可以直接進行修改,或者在actions
中修改,或者使用它的$patch
方法進行修改
pinia
中沒有了modules
,如果想使用多個store,直接使用defineStore
定義多個store傳入不同的id即可
更好的TS支持,不需要創建自定義的復雜包裝器來支持TS
vue 官方提供了v-text、v-for、v-model、v-if 等常用的指令。除此之外vue 還允許開發者自定義指令。面試經常會問什么是自定義指令?你用自定義指令做過哪些功能?
回答1:什么是自定義指令?
自定義指令包含局部指令和全局指令,在模板中使用指令前必須先使用directives
選項注冊。局部指令指在某個組件中注冊,而全局則是將指令注冊到全局,通常在main.js中注冊。
自定義指令由一個包含類似組件生命周期鉤子的對象來定義。它的生命周期鉤子包含created
,beforeMount
,mounted
,beforeUpdate
,updated
,beforeUnmount
,unmounted
,
常用的鉤子為mounted
和 updated
,它接受el
,binding
等參數.binding
參數的值一般包含綁定到這個元素上的信息,比如下面這個指令
<div v-example:foo.bar="baz">
它的binding會是這個對象
{
arg: 'foo',
modifiers: { bar: true },
value: /* `baz` 的值 */,
oldValue: /* 上一次更新時 `baz` 的值 */
}
回答2:你用自定義指令做過哪些功能?
數據埋點,通過綁定自定義事件傳入點擊當前元素需要埋點的事件名,在指令中監聽當前元素的點擊事件后調用后臺接口將事件名傳入
權限控制,通過綁定自定義事件傳入控制當前元素的權限字段,在指令中獲取到當前元素根據權限字段來控制該元素的狀態(顯示,隱藏等)
...
官網描述
<KeepAlive>
是一個內置組件,它的功能是在多個組件間動態切換時緩存被移除的組件實例。
回答
通常我們切換組件的時候,上一個組件就會被銷毀,而當我們使用<KeepAlive>
將其包裹的話這個組件就會被緩存,當這個組件再一次被顯示時就會保留之前的狀態。
keep-alive
接收兩個屬性include
和 exclude
,分別代表哪些組件要用緩存和哪些不需要緩存,它接收組件的名字數組,字符串或者正則,當我們使用動態組件component
或者路由router-view
的時候可以使用
keep-alive
還接收max
屬性表示最大緩存實例數,如果超出這個數則最久沒有被訪問的緩存實例將被銷毀。
keep-alive
有兩個生命周期,分別是activated
和deactivated
,activated
鉤子會在首次掛載或者每次從緩存中被重新插入的時候調用。deactivated
鉤子則是在組件從DOM上移除或者組件卸載時調用
vue3中已經沒有Mixin
這個概念了,所以未來被問到的幾率會越來越小,但是目前被問到的頻率還是很高的。一般會它的概念以及優缺點,有時還會問它與父組件的生命周期執行順序
vue官網描述:
混入 (mixin) 提供了一種非常靈活的方式,來分發 Vue 組件中的可復用功能。一個混入對象可以包含任意組件選項。當組件使用混入對象時,所有混入對象的選項將被“混合”進入該組件本身的選項。
回答1.Mixin
的作用將組件的公共邏輯提取出來,哪個組件需要用到時,直接將提取的這部分混入到組件內部即可
2. Mixin
的生命周期會在父組件生命周期之前執行,如果Mixin
中的屬性或者方法與父組件沖突則會使用父組件中的
2. 優點:可以降低代碼冗余提高邏輯復用性。
3. 缺點:命名容易沖突,不好追溯源,后期排查不方便
這道題問道的頻率極高,就我經歷的多場面試幾乎都會問到,而且是面試到vue方面的開門題。
下面是我自己的理解回答,以vue2為例,大家可以借鑒參考
vue的響應式原理是根據Object.defineProperty
這個api來對數據進行劫持并結合發布者-訂閱者模式實現的
首先會利用Object.defineProperty
中的get
函數來對vue中的data的所有屬性進行訪問劫持,中間會涉及到劫持data中更深層次的屬性需要遞歸調用劫持方法。這里是通過一個Observer
類實現的
劫持到每一個屬性后會給這個屬性綁定多個訂閱者watcher
,因為一個屬性可能被用在很多地方;而這個watcher
中則包含更新視圖的函數update
。
watcher
和屬性的對應關系以及和視圖的聯系則是通過編譯模板Compile
類來實現的。Compile
中會拿到整個dom對象,然后遍歷元素子節點獲取到使用過vue中data屬性的則給該屬性直接添加一個watcher
并賦予一些更新當前視圖的方法.
每個屬性的多個訂閱者watcher
都會被添加到對應的數組中,這里則是通過Deps
類實現的,初始化watcher
的時候會調用Deps
中的addSub
方法將對應watcher
添加該類的Subs
數組中
當data中的某個屬性發生改變時則會觸發Object.defineProperty
中的set
函數,這時便會調用該屬性的Deps
類中的notify
函數遍歷Subs
數組中的訂閱者watcher
并調用其函數update
去觸發視圖的更新
一般問完響應式原理可能會問這兩者的區別
回答
Object.defineProperty
只能代理屬性,Proxy
代理的是對象。
對象上新增屬性,Proxy
可以監聽到,Object.defineProperty
不能。
Object.defineProperty
的代理行為是在破壞原對象的基礎上實現的,Proxy 則不會破壞原對象,只是在原對象上覆蓋了一層。
數組新增修改,Proxy
可以監聽到,Object.defineProperty
不能。
Proxy
不兼容IE11
及以下
vue3新增了兩個內置組件分別是Teleport
和Suspense
。
Teleport
組件
可以稱之為傳送門,作用將其插槽內容渲染到 DOM 中的另一個位置,接收兩個參數to(要去的位置)和disabled(是否留在原位置)。接收比如下面代碼
<teleport to="#popup">
<video src="./my-movie.mp4">
</teleport>
video將會被傳送到id為popup的元素下。
Suspense
組件
<Suspense>
組件用于協調對組件樹中嵌套的異步依賴的處理。
它一般用于包裹多個異步組件處理多個異步組件加載前與完成后的統一狀態
<Suspense>
組件有兩個插槽:#default
和 #fallback
,在初始渲染時,<Suspense>
將在內存中渲染其默認的插槽內容。如果在這個過程中遇到任何異步依賴,則會進入掛起狀態等待異步組件加載完畢。在掛起狀態期間,展示的是 #fallback
插槽內容
關于nextTick會問到它的用法,然后是它的原理,然后還可能問到JS的時間循環機制。
問題1:vue中的nextTick是干什么用的?
這個其實比較簡單,用過都知道它是干嘛的,vue官方的解釋是:
在下次 DOM 更新循環結束之后執行延遲回調。在修改數據之后立即使用這個方法,獲取更新后的 DOM。
這是什么意思呢,其實vue中修改data不會立刻觸發dom更新;而是把需要更新的Watcher加入到queueWatcher隊列中,然后在合適的時機在nextTick中調用這些Watcher的更新函數進行dom更新,所以在data剛被修改的時候,我們是獲取不到更新后的dom的,這時候便需要調用nextTick函數在它的回調函數中獲取到變化后的dom
問題2:nextTick原理
nextTick原理是借助瀏覽器事件循環來完成的,因為每次事件循環之間都有一次視圖渲染,nextTick盡量在視圖渲染之前完成dom更新,所以nextTick優先使用的是promise(微任務)實現
每次執行nextTick時會將傳入的回調函數放入一個隊列中(callbacks數組),然后當在本次事件循環的同步代碼執行完畢后開啟一個微任務(promise或者MutationObserver)去依次執行這個callbacks中的回調函數。
但是當瀏覽器不支持promise的時候在vue2中會進行進行降級處理,依次使用setImmediate
、setTimeout
開啟一個宏任務執行callbacks
當一個data數據更新時對應的watcher便會調用一次nextTick,將它對應的dom更新操作作為回調函數放入callbacks中,所以當我們想獲取這個data更新后的dom需要在其值變化后也調用nextTick將回調函數傳入排在上個更新dom的回調函數后面,所以我們可以在這個nextTick的回調函數中獲取到更新后的data
這題在工作中有用嗎是???答案是沒有用,但是在面試中有用啊,所以我們要會回答?
問題1:什么是虛擬dom?
簡單來說就是一個描述dom結構的js對象
問題2:為什么要用虛擬dom?
每當我們用原生JS或者JQ操作DOM
時,瀏覽器會從頭開始進行DOM
樹的構建,頻繁的操作DOM
開銷是很大的。
而虛擬DOM
就是為了減少這些操作的,虛擬DOM
首先會通過狀態生成一個虛擬節點樹(js對象),然后使用虛擬節點樹進行渲染。當某些狀態發生變更時會生成新的虛擬DOM節點樹,然后與上一次虛擬DOM節點樹進行比較(diff),從而找到差異的部分,最后渲染到真實的DOM節點上面
問題3:說一下diff算法
diff算法的本質是找出兩個對象之間的差異,目的是盡可能復用節點。在vue中是當狀態發生改變,用來計算改變后的虛擬DOM與改變前的虛擬DOM之間的差異的算法。
讀到這里,這篇“Vue有哪些高頻面試題”文章已經介紹完畢,想要掌握這篇文章的知識點還需要大家自己動手實踐使用過才能領會,如果想了解更多相關內容的文章,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。