這篇文章為大家總結分享一些Vue面試題(附答案解析),帶你梳理基礎知識,增強Vue知識儲備,值得收藏,快來看看吧!
1. 簡述Vue 生命週期
#答案想法:
#回答範例:
生命週期這個詞應該是很好理解的,在我們生活中就會常常碰到,例如談到一個人的生命週期,我們會說人這一生會經歷嬰兒、兒童、青少年、青年、中年、老年這幾個階段。 而
Vue
的生命週期也是如此,在Vue
中的每個元件都會經歷從建立到掛載到更新再到銷毀這幾個階段,而在這些階段中,Vue
會運行一種叫做生命週期鉤子的函數,方便我們在特定的階段有機會添加我們自己的程式碼。Vue 生命週期總共可以分為
8
各階段:建立前後、掛載前後、更新前後、銷毀前後,以及一些特殊場景的生命週期(keep-alive
激活時、捕獲後代組件錯誤時)。Vue3
中也新增了三個用於偵錯和服務端渲染場景。-
這幾個階段對應的鉤子函數API依序為:
#beforeCreate
create
beforeMount
#mounted
beforeUpdate
updated
activated(keep-alive 啟動時呼叫)
deactivated(keep-alive 停用時呼叫)
beforeDestory
destoryed
errorCaptured(捕獲子孫元件錯誤時呼叫)
。在Vue3 中的變化絕大多數只要加上前綴on 即可,例如
mounted
變成onMounted
,除了beforeDestroy
和destroyed
被重新命名為beforeUnmount
# 和unMounted
(這樣與前面的beforeMount
和mounted
對應,強迫症表示很讚?) beforeCreate
# 在元件建立前調用,通常用於外掛程式開發中執行一些初始化任務;created
元件建立完畢調用,可以存取各種數據,請求介面資料等;mounted
元件掛載時調用可以存取資料、dom
元素、子元件等;beforeUpdate
更新前呼叫此時view
層尚未更新,可用來取得更新前的各種狀態;updated
完成更新時調用此時view層已經完成更新,所有狀態已經是最新的了;beforeUnmount
實例被銷毀前調用,可用於一些定時器或訂閱的取消;unMounted
銷毀一個實例時調用可以清理與其他實例的鏈接,解綁它的全部指令以及事件監聽器。在Vue3 中:
setup
是比created
先執行的;而且沒有beforeCreate
和created
。
2. Vue 中如何做權限管理
權限管理一般需求就是對頁面權限和按鈕權限的管理
-
具體實作的時候分前端實作與後端實作兩種方案: 前端方案會把所有路由資訊在前端配置,透過路由守衛要求使用者登錄,使用者登入後根據角色過濾出路由表,然後在動態加入路由。例如我會設定一個
asyncRoutes
數組,需要認證的頁面在路由的meta
中加入一個#roles
字段,等取得使用者角色之後取兩者的交集,若結果不為空則說明可以存取。過濾結束後剩下的路由就是使用者能存取的頁面,最後透過router.addRoutes(accessRoutes)
方式動態加入路由即可。後端方案會把所有頁面路由資訊存在資料庫中,使用者登入的時候會根據其角色查詢得到其能存取的所有路由資訊回傳給前端,前端再透過
addRoute
動態新增路由資訊。按鈕權限的控制通常會實作一個指令,例如
v-permission
,將按鈕要求角色透過值傳給v-permission
指令,在指令的mounted
鉤子中可以判斷目前使用者角色和按鈕是否存在交集,有就保留按鈕,沒有就移除按鈕。 純前端方案的優點是實作簡單,不需要額外權限管理頁面,但是維護起來問題比較大,有新的頁面和角色需求就要修改前端程式碼和重新打包部署;服務端方案就不存在這個問題,透過專門的角色和權限管理頁面,配置頁面和按鈕權限信息到資料庫,應用每次登陸時所獲取的都是最新的路由資訊。
自己的話:權限管理一般分頁面權限和按鈕權限,而具體實現方案又分前端實現和後端實現,前端實現就是會在前端維護一份動態的路由數組,透過使用者登入後的角色來篩選它所擁有權限的頁面,最後透過addRoute
將動態加入router
中;而後端實現的不同點就是這些路由是後端回傳給前端,前端再動態加入進去的。
按鈕權限一般會實作一個 v-permission
,透過判斷使用者有沒有權限來控制按鈕是否顯示。
純前端方案的優點是實現簡單,但是維護問題大,有新的頁面和角色需求都需要改程式碼重新打包部署,服務端則不存在這個問題。
3. Vue 中雙向綁定的使用和原理
#回答思路:
- ##什麼是雙向綁定?
- 雙向綁定的好處?
- 在什麼地方使用雙向綁定?
- 雙向綁定的使用方式、使用細節、Vue3中的變化
- 原理實作描述
回答:
- Vue中的雙向綁定是指令
v-model
,它可以綁定一個響應式數據到視圖,同時視圖中變化也能改變該值。
v-model
是語法糖,它的原理(預設請情況下)就是透過
:value將變數掛到
dom上,再透過
input事件監聽
dom的變化改變變數的值。使用
v-model的好處是方便呀,減少了大量的繁瑣的事件處理,提高開發效率。
- 通常在表單上使用
v-model
,也可以在自訂元件上使用,表示某個值得輸入和輸出控制。
- 可以結合修飾符做進一步限定(lazy/number/trim),用在自訂元件上時有些不同,它相當於是給了子元件一個
modelValue
的屬性和
update:modelValue的事件; 在Vue3 中也可以用參數形式指定多個不同的綁定,如
v-model:foo這時候就相當於給了子元件一個
foo的屬性和
update:foo的事件。
v-model
作為一個指令,它的原理就是Vue 編譯器會把它轉換成
value屬性綁定和input的監聽事件,上面說過是預設情況下,實際上編譯器會根據表單元素的不同分配不同的事件,例如checkbox和
radio類型的
input會轉換為
checked和
change事件。
4. Vue 元件之間通訊有哪些?
Vue 元件之間通訊有以下這麼多種:
props
#
$emit
、$on
、$off
、$once
(後三者在Vue3中已被廢除)$children
(Vue3中廢除)、$parent
$attrs
、$listeners
(Vue3中廢除)-
ref
$root
eventbus
(Vue3中不好使了,需要自己包裝)#vuex
、pinia
-
provide inject
- #以上的方法長按使用情境可以分為:
$parent父子元件之間可以使用
props
/$emit
/ / - ref
/
$attrs
$parent#兄弟元件之間可以使用
/
/ eventbus /
vuex#跨層及元件之間可以使用
- /
- vuex pinia
/
provide inject
- #5.你了解哪些Vue 效能最佳化方法?
App#路由懶載入:有效分割
尺寸,存取時才非同步載入 -
keep-alive<pre class='brush:php;toolbar:false;'>const router = createRouter({ routes: [ { path : &#39;/foo&#39;, component: () => import(&#39;./foo.vue)} ] })</pre>
快取頁面:避免重複建立元件實例,且能儲存快取元件狀態 #<pre class='brush:php;toolbar:false;'><keep-alive> <router-view v-if="$route.meta.keepAlive == true"></router-view> </keep-alive> <router-view v-if="$route.meta.keepAlive != true"></router-view></pre>
使用
v-show
重複使用DOM
:避免重複建立元件#v-for
遍歷避免同時使用v-if
(實際上這在Vue3 中是錯誤的寫法)- v-once 和
- v-memo
#:不再變化的資料使用
v-once
;按條件跳過更新時使用v-memo
-
#長列表效能最佳化:如果是大數據長列表,可採用虛擬滾動,只渲染一小部分區域的內容。一些開源程式庫(
vue-virtual-scroll-gridvue-virtual-scroller
/ ) - ##事件的銷毀:Vue元件銷毀時,會自動解綁它的全部指令以及事件監聽器,但是僅限於元件本身的事件。
-
指令(參考項目:圖片懶加載,自訂
v-lazy vue-lazyload
第三方外掛程式按需引入
element-plus 避免體積太大
- #子元件分割策略:較重的狀態元件適合分割
-
SSR
服務端渲染解決首屏渲染慢的問題 - 6. 刷新後Vuex 狀態遺失怎麼解決?
- 想法:
為什麼刷新後 Vuex 狀態為什麼會遺失?
- 解決方法
第三方函式庫以及原理探討
##個人理解
##回答:
因為Vuex 只是在記憶體中儲存狀態,刷新後就會遺失,如果要持久化就要存起來。
可以是用
localStorage儲存
Vuex的狀態,
store中把值取出來當作
state的初始值,提交
mutation的時候就存入
localStorage。
vuex-persist、
vuex-persistedstate
mutation 變化做統一處理。
localStorage怎麼辦?那我 Vuex
裡的狀態不是也改變了?第二是因為localStorage API 的原因只能儲存字串,所以我們只能將資料透過JSON.stringify
轉換為字串,而當我們儲存的資料為- Map
- 、
Set
、 Function - 這種引用型別的資料時,
JSON.stringify
轉換後會變味 {} - 而丟失。
- 對應第一個問題我的解決方法是可以透過監聽
storage
事件來清除資料
window.addEventListener("storage", function () { localStorage.clear(); window.location.href = '/login' console.error("不要修改localStorage的值~~~"); });對於第二個問題沒辦法了,只能選擇不適用
Map 和Set
這種引用類型。-
7. Vue3 為什麼用Proxy 取代defineProperty ?
#########defineProperty的問題#############Proxy的優點############其他考慮##############################################################。 ############回答:###################JS### 中做屬性攔截常見的方式有三種:###defineProperty ###、###getter/setters### 和###Proxy#######思路:
##屬性攔截的幾種方式
Vue2
中使用defineProperty
的原因是, 2013 年只能使用这种方式,由于该API
存在一些局限性,比如对于数组的拦截有问题,为此Vue
需要专门为数组响应式做一套实现。另外不能拦截那些新增、删除属性;最后defineProperty
方案在初始化时需要深度递归遍历处理对象才能对它进行完全拦截,明显增加了初始化的时间。以上两点在
Proxy
出现后迎刃而解,不仅可以对数组实现拦截,还能对Map
、Set
实现拦截;另外Proxy
的拦截也是懒处理行为,如果用户没有访问嵌套对象,那么也不会实施拦截,这就让初始化的速度和内存占用改善了。Proxy
有兼容性问题,完全不支持IE
8. 怎么实现路由懒加载?
思路:
必要性
何时用
怎么用
使用细节
回答:
当打包构建时,Javascript 抱回变得非常大,影响页面加载。利用路由懒加载我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应最贱,这样更加高效,是一种优化手段。
一般来说,对于所有的路由都使用动态导入是个好主意
给
component
选项配置一个返回 Promise组件的函数就可以定义懒加载路由.例如:
{ path: '/login', component: () => import('../views/login/Login.vue') },
结合注释
{ path: '/login', component: () => import(/* webpackChunkName: "login" */'../views/login/Login.vue') },
vite中结合rollupOptions定义分块 5. 路由中不能使用异步组件
9. history模式 和 hash 模式有何区别?
Vue-Router 有三个模式,其中 history 和 hash 更为常用。两者差别主要在显示形式和部署上,
hash模式在地址栏现实的时候有一个
#
,这种方式使用和部署都较简单;history模式url看起来更优雅没关,但是应用在部署时需要做特殊配置,web服务器需要做回退处理,否则会出现刷新页面404的问题。在实现上
hash
模式是监听hashchange
事件触发路由跳转,history
模式是监听popstate
事件触发路由跳转。
10. 说说 nextTick 的使用和原理?
在
Vue
中nextTick
是等待下一次DOM
更新刷新的工具方法。-
Vue
有一个异步更新策略,意思是如果数据变化,Vue
不会立刻更新DOM
,而是开启一个队列,把组件更新函数保存在队列中,在同一时间循环中发生的所有数据变更会异步的批量更新。这一策略导致我们对数据的修改不会立刻体现在DOM
上,此时如果想要获取更新后的DOM
状态,就需要使用nextTick
nextTick
接受一个函数,我们可以在这个函数内部访问最新的DOM
状态 在开发时,有两个场景我们会用到nextTick
:-
created
中想要获取DOM
; - 响应式数据变化后获取
DOM
更新后的状态;
-
nextTick
的原理:在Vue
内部,nextTick
之所以能够让我们看到DOM
更新后的结果,是因为我们传入的callback
会被添加到队列刷新函数的后面,这样等队列内部的更新函数都执行完毕,所有DOM
操作也就结束了,callback
自然能够获取最新的DOM
值。
11. v-for 和 v-if 优先级
先回答答案:在 vue2
中, v-for
的优先级更高
但是在 vue3
中, v-if
的优先级更高
拓展:无论什么时候,我们都不应该把 v-for
和 v-if
放在一起,
怎么解决呢?一是可以定义一个计算属性,让 v-for
遍历计算属性。二是可以把 if
移到内部容器里(ul
ol
)或者把v-for
移植外部容器(template
)中
#12. 如何監聽 Vuex 狀態變更?
watch
store.subscribe()
watch
方式,可以以字串形式監聽$store.state.xx
; subscribe
方法參數是一個回呼函數,回呼函數接受mutation
物件和state
對象,可以透過mutation.type
判斷監聽的目標。
wtach 方法更簡單好用, subscribe
會略繁瑣,一般用vuex
插件中(可以提一下vuex的持久化插件vuex-persist
、vuex-persistedstate
)
13. 你覺得Vuex 有什麼缺點?
不支援持久化,頁面刷新狀態就會遺失
使用模組比較繁瑣
-
#不支援
ts
(或很不友善)
vue3 pinia 會是更好的組合。
14. ref 和reactive 異同點?
#兩者都能傳回響應式對象,
ref
傳回的是一個響應式Ref
對象,reactive
傳回的是響應式代理對象。ref
通常是處理單一值得響應式,reactive
用於處理物件類型的資料響應式ref
需要透過.value
訪問, 在視圖中會自動脫ref
,不需要.value
,ref
可以接收物件或陣列但內部仍然是reactive
實現的;reactive
如果接收Ref
物件會自動脫ref
;使用展開運算子展開reactive
傳回的響應式物件會使其失去回應性,可以結合toRefs()
將值轉換為Ref
物件後再展開。reactive
內部使用Prxoy
# 代理攔截物件各種操作,而ref
內部封裝一個RefImpl
類,設定get value/set value
,攔截使用者對值得存取。
16. Vue 中如何擴充一個元件?
邏輯擴充:
mixins
、extends
、composition api
:內容擴充:slots
mixins
很靈活,但會衝突很混亂。 extends
是一個不太常用的選項,更 mixins
的不同是它只能擴展單個對象,優先權比 mixins
高。
混入的資料和方法 不能明確判斷來源 而且可能和目前元件內變數 產生命名衝突,composition api 可以很好地解決這些問題,利用獨立出來的響應式模組可以很方便的編寫獨立邏輯並提供響應式資料局,增強程式碼的可讀性和維護性。
擴充:Vue.mixin(全域混入) Vue.extend(有點像是類別/元件的繼承建立一個子類別)
17. vue -loader 是什麼?
vue-loader
是用來處理單一檔案元件(SFC)的webpack loader因為有了
vue-loader
,我們才能用.vue
檔案形式編寫程式碼,將程式碼分割為template
script
style
webpack
在打包的時候,會以loader
的方式呼叫vue-loader
vue-loader
被執行時,它會對SFC
中的每個語言區塊用單獨的loader
鏈處理,最後將這些單獨的區塊組裝成最終的元件模組
#18. 子元件能否修改父元件資料
#不能直接改。
元件化開發中有一個單向資料流原則,不在子元件修改父元件資料是個常識
如果你確實需要改,請透過emit向父元件發送事件,在父元件中修改
19. 怎麼定義動態路由,怎麼取得傳過來的動態參數?
我麼可以在路徑中使用一個動態欄位來實現,例如/users/:id
其中 :id
是路徑參數。
可以透過 this.$route.parmas
取得,參數還可以有多個,$route
物件也公開了其他有用的資訊如query
hash
等。
20. 說說對 Vue 資料響應式的理解
想法:
什麼是響應式?
為什麼vue需要響應式?
有什麼好處?
vue的響應式怎麼實現的,有哪些優缺點?
vue3中的回應式的新變化
#回答:
- ##資料響應式就是能夠監控到資料變化並且做出回應的一種機制
- 在
vue
中要解決的一個核心問題就是連接資料層和視圖層,透過資料變化驅動視圖更新,要做到這點就需要對資料做響應式處理。
- 透過資料響應式加上虛擬
DOM
和
patch演算法,我們只需要操作數據,關心業務,完全不需要接觸繁瑣的
DOM操作,打打提升了開發效率,降低開發難度。
vue2
中實作資料回應式的核心是透過
Object.defineProperty()方法對資料進行攔截,當
get資料時做依賴收集
set資料時做更新通知。這種機制很好的及絕了資料響應式的問題,但是實際使用也存在缺點,例如在
初始化時的遞歸遍歷會造成效能損失;無法監聽新增或刪除屬性,在vue中要透過像
Vue.set/delete這種特定的
API才能實現對物件陣列屬性的新增和刪除,而且也不支援
Ma、
Set這些資料結構,
- #為了解決這些問題,
Vue3
重寫了這部分實現,利用的是
ES6中的
Proxy代理要回應化的資料。它有很多好處,初始化效能和記憶體都大幅改善,也不需要特殊的
API,但不支援
IE瀏覽器。
21. 從template 到render 做了什麼
#問template 到
render 的過程其實是問的vue
編譯器 工作原理。
想法:
- 引入編譯器概念
- 說明編譯器的必要性
- 闡述編譯器工作流程
回答:
Vue
中有一個獨特的編譯模組,稱為
compiler,它的主要作用是將
template編譯為
js# 可執行的
render函數
- 之所以需要這個編譯過程是為了方便我們高校的編寫試圖模版。相較而言,我們還是更願意用
HTML
來寫視圖,直覺且有效率。手寫
render函數不僅效率低下,而且失去了被編譯器的最佳化能力。
Vue
編譯器首先會對
template進行解析(
Parse),結束後會得到一個抽象語法樹
AST,然後對
AST進行深度加工轉換(
transform),最後將得到的
AST產生為
js程式碼,也就是
render函數
22. 如何快取與更新元件
- ##快取元件可以使用
- keep-alive
元件,include 和exclude 可以指定包含不包含哪些元件。
- Vue3
結合
vue-router
使用變化非常大,之前是keep-alive
包含router -view
,現在是router-view
包含keep-alive
快取後如果想要取得資料可以使用 - actived
鉤子或
beforeRouteEnter
(vue-router
的一個守衛) - keep-alive
是一個通用元件,它內部定義了一個
map
,快取創建過的元件實例,它傳回的渲染函數內部會尋找內嵌的component
元件對應元件的vnode
,如果改組件在map中存在就直接回傳它。由於component
的is
屬性是一個響應式數據,因此只要它變化,keep-alive
的render
函數就會重新執行。
23. 虛擬DOM
#虛擬
DOM
是什麼? 虛擬DOM
的本質就是一個Javascript
物件。為什麼要引入虛擬
DOM
? (好處) 它能有效減少操作DOM
的次數,方便實現跨平台#虛擬DOM如何產生?
compiler
編譯器會把template
模版編譯成渲染函數,接下來在mount
掛載的過程會呼叫這個渲染函數,回傳的物件就是虛擬DOM
。掛載結束後,會進入更新流程。如果某些響應式資料發生變化,將會造成元件重新render
,此時會產生新的虛擬DOM
,和上次渲染結果做diff
#操作,最小量的操作dom
,從而有效率地更新視圖。
24. 什麼是非同步元件
非同步元件就是不會立即載入而是會在需要的時候載入的組件。在大型應用中,我們需要分割程式碼為更小的區塊試就可以用非同步元件。
不僅可以在路由切換時懶載入元件,還可以在元件中使用非同步元件,從而更細的分割程式碼。
使用非同步元件最簡單的方式是直接給
defineAsyncComponet
指定一個loader
函數,結合ES 模組動態導入函數import
可以快速實現。Vue3
也可以結合Suspense
元件使用非同步元件。非同步元件容易和路由懶加載混淆,實際上不是一個東西。非同步元件不能用來定義懶載入路由上,處理它的是
Vue
框架,處理路由元件載入的是vue-router
。但是可以在懶加載的路由組件中使用非同步組件。
25. 說說Vue長列表最佳化想法
- 避免大數據量:可以採用分頁的方式取得
- 避免渲染大量資料:vue-virtual-scroller等虛擬捲動方案,只渲染視窗範圍內的資料
- 避免更新:可以使用
v-once
方式只渲染一次 - 優化更新:透過v-memo快取組數,有條件更新,提高服用,避免不必要更新
- 按需載入資料:可以採用
懶載入
方式,在用戶需要的時候在載入資料。
26. computed & watch
#computed
是計算屬性,watch
#是偵聽器。computed
通常用於處理模版中複雜的邏輯,而watch
通常用於需要監聽一個響應式物件的變化而做一些操作的時候watch
可以進行非同步操作,computed
不行。計算屬性傳遞一個物件有
set
和get
兩個選項,是它稱為即可讀又可寫的計算屬性,如果傳遞的是函數的話預設就是get
選項,watch
可以傳遞一個對象,設定deep、immediate等選項vue3
中watch
發生了一些變化,例如不能再偵測一個點操符之外的字串表達式,reactivity API
中新出的watch
、watchEffect
可以完全取代watch
選項,而且功能更強大
27.SPA 和SSR的區別是什麼?
SPA
(Single Page Application)是單一頁面應用程式。一般也稱為客戶端渲染,簡稱CSR
。 SSR(Server Side Render) 即服務端渲染。一般也稱為多頁面應用程式(Mulpile Page Application),簡稱 MPA。SPA
只會首次要求html
文件,後續只需要請求JSON
資料即可,因此使用者體驗更好,節約流量,服務端壓力也較小。但是首屏載入的時間會變長,而且SEO
不友善。為了解決以上缺點,就有了SSR
方案,由於HTML
內容在伺服器一次生成出來,首屏加載快,搜尋引擎也可以很方便的抓取頁面資訊。但同時SSR
方案也會有效能,開發受限等問題。選擇上,如果有首屏載入優化需求,SEO需求時,就可以考慮SSR。
但不是只有這一種替代方案,例如對一些不常變化的靜態網站,SSR反而浪費資源,我們可以考慮預先渲染的方案。另外
nuxt.js/next.js
中給我們提供了SSG靜態網站產生方案也是很好的靜態網站解決方案,結合一些CI手段,可以起到很好的最佳化效果。
28. diff 算法
回答思路:
diff算法是干什么的?
必要性
何时执行
具体执行方式
拔高:说一下vue3中的优化
回答:
Vue
中的diff
算法称为patching
算法,虚拟DOM要想转化为真实DOM就需要通过patch
方法转换。最初
Vue1.x
视图中农每个依赖均有更新函数对应,可以做到精确更新,因此不需要虚拟DOM
和patching
算法支持,但是这样粒度过细导致Vue1.x
无法承载较大应用;Vue2.x
中为了降低Watcher
粒度,每个组件只有一个Watcher
与之对应,此时就需要引入patching
算法才能精确找到发生变化的地方并高效更新。vue
中diff
执行的时刻是组件内响应式数据变更触发实例执行其更新函数时,更新函数会再次执行render函数
获得最新的虚拟DOM
,然后执行patch函数
,对比新旧虚拟DOM,将其转化为对应的DOM
操作。-
patch
过程是一个递归过程,遵循深度优先、同层比较的策略;以vue3
的patch
为例:- 首先判断两个节点是否为相同同类节点,不同则删除重新创建
- 如果双方都是文本则更新文本内容
- 如果双方都是元素节点则递归更新子元素,同时更新元素属性
- 更新子节点时又分了几种情况:
- 新的子节点是文本,老的子节点是数组则清空,并设置文本;
- 新的子节点是文本,老的子节点是文本则直接更新文本;
- 新的子节点是数组,老的子节点是文本则清空文本,并创建新子节点数组中的子元素;
- 新的子节点是数组,老的子节点也是数组,那么比较两组子节点,更新细节blabla
vue3
中引入的更新策略:编译期优化patchFlags
、block
等
29. 如何从0到1架构一个Vue项目,说说有哪些步骤,插件,目录结构怎么组织
从 0 创建项目我大致会做以下事情:项目构建、引入必要插件、代码规范、提交规范、常用库和组件
目前vue3项目我会用vite或者create-vue创建项目
接下来引入必要插件:vue-router、vuex/pinia、element-plus、antd-vue、axios等等
其他常用的库有 像lodash、dayjs、nprogress等等..
下面是代码规范: editorconfig、prettier、eslint
最后是提交规范,可以使用husky、Commitizen
目录结构我喜欢按照下面的结构来
+ |- /src + |- /assets 存放资源 + |- /img + |- /css + |- /font + |- /data + |- base-ui 存放多个项目中都会用到的公共组件 + |- components 存放这个项目用到的公共组件 + |- hooks 存放自定义hook + |- views 视图 + |- store 状态管理 + |- router 路由 + |- service 网络请求 + |- utils 工具 + |- global 全局注册、全局常量..
30. 你如何实现一个Vue-Router
一个 SPA
应用的路由需要解决的问题时页面跳转内容改变同时不刷新,同时路由还需要已插件形式存在,所以:
-
首先我会定义一个
createRouter
函数,返回路由器实例,实例内部做几件事;- 保存用户传入的配置项
- 监听
hash
或者popstate
事件 - 回调里根据
path
匹配对应路由
-
将
router
定义成一个Vue
插件,即实现install
方法,内部做两件事:- 实现两个全局组件:
router-link
和router-view
,分别实现页面跳转和内容显示 - 定义两个全局变量:
$router
和$route
,组件内可以访问当前路由和路由器实例
- 实现两个全局组件:
31. 什么情况需要使用Vuex模块?
在项目规模变大的之后,单独一个store对象会过于庞大臃肿,此时通过模块方式可以拆分来便于维护
可以按之前规则单独编写资规模代码,然后在主文件中通过
modules
选项组织起来:createStore({modules: {...}})
使用時需要注意存取子模組狀態時需要加上註冊模組名稱。但同時
getters
、mutations
和actions
又在全域空間中,使用方式和之前一樣。如果要做到完全拆分,需要在子模組加上namespace
選項,此時再訪問它們就要加上命名空間前綴。模組的方式可以分割程式碼,但是缺點也很明顯,使用起來比較繁瑣,容易出錯,而且類型系統支援很差,不能給我們帶來幫助。 pinia 顯然在這方面有了很大改進,是時候切換過去了。
32. vue 元件為什麼只能有1個根節點
vue2
中元件確實只能有一個跟,但vue3
中元件已經可以多根元件了。之所以需要這樣是因為
vdom
是一顆單根樹狀結構,patch
方法在遍歷的時候從根節點開始遍歷,它要求只有一個根節點。元件也會轉換為一個vdom
,自然應該滿足這個要求。vue3
中之所以可以寫多個根節點,是因為引入了Fragment
的概念,這是一個抽象的節點,如果發現元件時多根的,就建立一個Fragment
節點,把多個根節點當作它的children
。將來pathch
的時候,如果發現是一個Fragment
節點,則直接遍歷children
建立或更新。
33. v-once 使用場景有哪些?
v-once
是vue
的內建指令,作用是只渲染指定元件或元素一次,並跳過未來對其更新。如果我們有一些元素或元件再初始化渲染之後不再需要變化,這種情況下適合使用
v-once
,這樣哪怕這些資料變化,vue
也會跳過更新,是一種程式碼最佳化手段。我們只需要作用的元件或元素上加上
v-once
即可。
補充:
vue3.2
之後,又增加了v-memo
,這個指令可以有條件的快取模板並控制他們的更新。v-once
的原理:編譯器發現有v-once
時,將第一次計算結果存入快取對象,元件再次渲染時就會從快取獲取,從而避免再次計算。
34. 什麼場景使用嵌套路由
- 在平時開發中,應用的有些介面是由多層嵌套的元件組合而來的,在這種情況下,
url
各部分通常對應某個嵌套的元件,vue-router
中可以使用巢狀路由表示這種關係。 - 表現形式是在兩個路由間切換時,他們有公用的視圖內容。此時通常會擷取一個父元件,內部放上
view-router
,從而形成物理上的嵌套,和邏輯上的嵌套對應起來。定義嵌套路由時使用children
屬性組織嵌套關係 - 原理上是在
router-view
元件內部判斷其所處嵌套的深度,將這個深度作為匹配元件數組matched
的索引,取得對應渲染元件並渲染之。
如果你說不出來,可以直接舉例。當我開發一個頁面時,如果需要顯示一個頂部導覽欄,透過導覽列跳到不同的頁面,而頂部的導覽列又必須要在每個頁面顯示時,就可以使用嵌套路由;還可以舉例,當我需要查看某個清單的詳情頁面時,往往需要嵌套路由(detail/:id
)
35. 如何監聽Vuex 狀態變化?
watch
store.subscribe()
watch
方式,可以以字串形式監聽$store.state.xx
; subscribe
方法參數是一個回呼函數,回呼函數接受mutation
物件和state
對象,可以透過mutation.type
判斷監聽的目標。
wtach 方法更簡單好用, subscribe
會略繁瑣,一般
36. Vue 實例掛載過程發生了什麼?
掛載實例的過程就是app.mount()的過程,整體上就做了兩件事:初始化和建立更新機制
初始化會建立元件實例、初始化元件狀態、建立各種響應式資料
簡歷更新機制這一步驟會立即執行一次元件更新函數,這會首次執行渲染函數並執行
patch
將前面獲得vnode
轉換為dom
;同時會建立它內部響應式資料和元件更新函數之間的依賴關係,這使得以後資料變更時會執行對應的更新函數。
37. key 的作用
key
的作用主要是為了更有效率的更新虛擬DOM
。key
是vue
在patch
過程中判斷兩個節點是否為相同節點的關鍵條件(另一個是元素類型),如果不設定key
,它的值就是undefined
#,vue
則可能永遠認為這是兩個相同節點,只能去做更新操作,這造成了大量的dom
更新操作,明顯是不可取的。實際使用的過程中必須設定
key
,而且應該盡量避免使用陣列索引,這可能導致一些隱藏bug
。
38. watch 和watchEffect
watchEffect
立刻執行函數,被動地追蹤它的依賴,傳入的函數即是依賴收集的資料來源,也是回呼函數;watch
偵測一個或多個響應式資料來源,在資料來源變更時呼叫一個回呼函數,透過immediate
選項也可以設定立即執行一次。watchEffect
是一種特殊的watch
。如果不關心響應式資料前後的值,可以使用watchEffect
。其他情況都可以用watch
。
39. 父子元件建立、掛載順序
parent created -> child created -> child mounted -> parent mounted
原因:Vue
創建是一個遞歸的過程,先建立父元件,有子元件就會建立子元件,因此創建時先有父元件再有子元件;子元件首次建立時會加入Mounted
鉤子到佇列,等到patch
結束再執行它們,可見子元件的mounted
鉤子是選進入到佇列中的,因此等到patch
結束執行這些鉤子時也先執行。
40. 說說你對Vuex 的理解
-
#vuex是專門為vue應用程式開發的狀態管理模式庫,
當你遇到多個元件共享狀態時或專案中的元件難以管理的時候就可以使用vuex,它以一個全域單例模式管理全域的狀態。
基本核心概念有state、mutation、action、getters、module等
說些使用過程的感受ts不友善模組使用繁瑣頁面刷新資料也會消失
41. 什麼是遞迴元件?使用場景有哪些?
如果某個元件透過元件名稱來引用它自己,這種情況就是遞迴元件。
類似
Tree
、Menu
這類元件,它們的節點往往包含子節點,子節點結構和父節點往往是相同的。這類組件的資料往往也是樹狀結構,這種都是使用遞迴元件的典型場景。
42. 你寫過自訂指令嗎?
使用自訂指令分為定義、註冊、和使用
#定義有兩種方式,物件和函數形式,前者類似元件定義,有各種生命週期;後者只會在
mounted
和updated
時執行註冊:可以使用
app.directive
全域註冊也可以透過選項局部註冊使用時在註冊名稱前加上v-即可。
v-copy
複製貼上-
#v-lazy
圖片懶載入 v-debounce
防手震#v-permission
按鈕權限#v-longpress
長按
#43. Vue3新功能
API 層面
Composition API
#setup
語法糖Teleport
傳送門#Fragments
可以多個根節點Emits
createRenderer
自訂渲染器SFC
狀態驅動css
變數(v-bind in<style></style>
)
##此外,Vue3在框架層級也有很多兩點和改進
- 更快
- 虛擬
DOM
重寫 - #編譯器最佳化:靜態提升、
patchFlags
、block
等 - 基於
Proxy
的響應式系統
- 虛擬
- #更小:更好的搖樹優化
- #更容易維護:TS 模組化
- 更容易擴展
- 獨立的響應化模組
- #自訂渲染器
##44. Vue3設計目標和最佳化點
最大設計目標就是替代Vue2,為了實現這一點,
Vue3 在以下幾個方面做了很大改進,如:易用性,框架性能、擴展性、可維護性、開發體驗等
- #易用性方面:主要有
API
簡化
v-model變成了
v-model和
sync修飾符的結合體。類似的還有
h(type,props,children)函數中的
props不用考慮區分屬性、特性、事件等,框架替我們判斷,易用性增。
- 開發體驗方面:新組成
Teleport
等都會簡化特定場景的程式碼編寫。
setup語法糖更是大幅提升了我們的開發體驗。
- 擴充功能方面提升: 如獨獨立的
reactivity
模組,
custom render API等
- 可維護性方面主要是
Composition API
,更容易寫出高復用性的業務邏輯。還有對TS支援的提升。
- 效能方面:編譯器最佳化、基於
Proxy
的響應式系統。
- 。 。 。
45. Vue3效能提升體現在哪些方面?
- 程式碼方面:全新的響應式API,基於
Proxy
實現,初始化事件和記憶體佔用均大幅改進;
- 編譯方面:做了更多編譯最佳化處理,例如靜態提升、動態內容標記、事件快取、區塊等,可以有效跳過大量diff過程
- 打包方面:更好的支援
tree-shaking
,因此體積更小,載入更快.(
因為vue3 所有的API都透過ES6模組化的方式引入,這樣就能讓webpack或rollup等打包工具在打包時對沒有用到API進行剔除,最小化bundle體積)
#46. $attrs 和
$listeners 是做什麼的?
$attrs 取得沒有在
props 中定義的屬性,
v-bind="$attrs" 可以用於屬性透傳
$listeners 用來取得事件,
vue3 中已經移除合併到
attrs 中,使用起來更方便
47. Composition API 和Option API 有何不同?
Composition API 是一組API,包括
Reactivity API、生命鉤子、依賴注入,使用戶可以透過匯入函數方式編寫元件,而
Options API 則透過宣告元件選項的物件形式編寫元件。
Composition API 更簡潔、邏輯重複使用更有效率。解決的過去
Options API 中
mixins 的各種缺點(會衝突很混亂);另外
Composition API 更自由,沒有
Options API 那樣固定的寫法,並且可以更有效的將邏輯代碼組織在一起,而不用東一塊西一塊搞得很混亂,最後
Composition API 擁有更好的類型推斷,對
ts 支持友好。
48. 你知道哪些Vue 最佳實踐
#編碼風格方面:
- ##元件命名時使用多字風格避免和html元素衝突
- 屬性名峰命名,模板或jsx中使用肉串命名
- v- for 務必加上key 且不要和v-if寫在一起''
- #路由懶載入減少應用程式尺寸
- SSR
減少首屏載入事件
- v-once
v-memo
長列表虛擬捲動技術 - 對於深層巢狀物件的大數據可以使用
- shallowRef
或
shallowReactive
降低開銷 #避免不必要的元件抽象 - ##49. mutation 和action 的差別?
mutation
用來修改stateaction
用來提交一個
mutation,而且
action 可以包含非同步操作
50. 如何從0實作vuex
要實作一個
- Store
- 儲存全域狀態
要提供修改狀態所需的API: commit({type, payload}) - ,
dispatch(type,payload)
實作Store
,可以定義Store
類,建構函式接受選項options
,設定屬性state
對外暴露狀態,提供commit
和dispatch
修改屬性。這裡需要設定 state
為響應式對象,同時將 Store
定義為一個 Vue
外掛(install方法)。
commit
可以取得使用者傳入mutations
並執行它,這樣可以依照使用者提供的方法修改狀態,dispatch
類似,但dispatch
需要傳回一個Promise
給使用者用於處理非同步結果。
以上是【整理總結】45+個Vue面試題,帶你鞏固知識點!的詳細內容。更多資訊請關注PHP中文網其他相關文章!

php中文网作为知名编程学习网站,为您整理了一些React面试题,帮助前端开发人员准备和清除React面试障碍。

本篇文章给大家总结一些值得收藏的精选Web前端面试题(附答案)。有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助。

作为近年来备受热捧的一门编程语言,Go语言已经成为众多公司与企业的面试热点。对于Go语言初学者而言,在面试过程中遇到相关问题时,如何回答是一个值得探讨的问题。下面列举五个常见的Go语言面试题及解答,供初学者参考。请介绍一下Go语言的垃圾回收机制是如何工作的?Go语言的垃圾回收机制基于标记-清除算法和三色标记算法。当Go程序中的内存空间不够用时,Go垃圾回收器

本篇文章带大家聊聊vue指令中的修饰符,对比一下vue中的指令修饰符和dom事件中的event对象,介绍一下常用的事件修饰符,希望对大家有所帮助!

如何覆盖组件库样式?下面本篇文章给大家介绍一下React和Vue项目中优雅地覆盖组件库样式的方法,希望对大家有所帮助!

本篇文章给大家分享50个必须掌握的Angular面试题,会从初学者-中级-高级三个部分来解析这50个面试题,带大家吃透它们!


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

MantisBT
Mantis是一個易於部署的基於Web的缺陷追蹤工具,用於幫助產品缺陷追蹤。它需要PHP、MySQL和一個Web伺服器。請查看我們的演示和託管服務。

VSCode Windows 64位元 下載
微軟推出的免費、功能強大的一款IDE編輯器

Dreamweaver Mac版
視覺化網頁開發工具

SublimeText3 英文版
推薦:為Win版本,支援程式碼提示!

記事本++7.3.1
好用且免費的程式碼編輯器