首頁 > web前端 > Vue.js > 主體

【整理總結】45+個Vue面試題,帶你鞏固知識點!

青灯夜游
發布: 2023-01-12 21:02:34
轉載
3040 人瀏覽過

這篇文章為大家總結分享一些Vue面試題(附答案解析),帶你梳理基礎知識,增強Vue知識儲備,值得收藏,快來看看吧!

【整理總結】45+個Vue面試題,帶你鞏固知識點!

1. 簡述Vue 生命週期

#答案想法:

  • Vue 生命週期是什麼?

  • Vue 生命週期有哪些階段?

  • Vue 生命週期的流程?

  • 結合實踐

  • 擴展:在Vue3 變化Vue 生命週期的變化【相關推薦:vuejs影片教學web前端開發

#回答範例:

  • 生命週期這個詞應該是很好理解的,在我們生活中就會常常碰到,例如談到一個人的生命週期,我們會說人這一生會經歷嬰兒、兒童、青少年、青年、中年、老年這幾個階段。 而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,除了beforeDestroydestroyed 被重新命名為 beforeUnmount# 和unMounted(這樣與前面的beforeMountmounted 對應,強迫症表示很讚?)

  • 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的監聽事件,上面說過是預設情況下,實際上編譯器會根據表單元素的不同分配不同的事件,例如checkboxradio 類型的input 會轉換為checkedchange 事件。

4. Vue 元件之間通訊有哪些?

Vue 元件之間通訊有以下這麼多種:

  • props#

  • $emit$on$off$once(後三者在Vue3中已被廢除)

  • $children(Vue3中廢除)$parent

  • $attrs$listeners(Vue3中廢除)

  • ref

  • $root

  • eventbus (Vue3中不好使了,需要自己包裝)

  • #vuexpinia

  • provide inject

  • #以上的方法長按使用情境可以分為:

    父子元件之間可以使用props /$emit/

    $parent
  • /
  • ref

    /

    $attrs

    #兄弟元件之間可以使用

    $parent
  • /
$root

/ eventbus /

vuex
  • #跨層及元件之間可以使用

eventbus
    /
  • vuex pinia

    / provide inject

  • #5.你了解哪些Vue 效能最佳化方法?

    #路由懶載入:有效分割

    App
  • 尺寸,存取時才非同步載入
  • <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:js;toolbar:false;">const router = createRouter({ routes: [ { path : &amp;#39;/foo&amp;#39;, component: () =&gt; import(&amp;#39;./foo.vue)} ] })</pre><div class="contentsignin">登入後複製</div></div>

    keep-alive
  • 快取頁面:避免重複建立元件實例,且能儲存快取元件狀態
  • #<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:js;toolbar:false;">&lt;keep-alive&gt; &lt;router-view v-if=&quot;$route.meta.keepAlive == true&quot;&gt;&lt;/router-view&gt; &lt;/keep-alive&gt; &lt;router-view v-if=&quot;$route.meta.keepAlive != true&quot;&gt;&lt;/router-view&gt;</pre><div class="contentsignin">登入後複製</div></div>使用v-show重複使用DOM:避免重複建立元件

  • #v-for 遍歷避免同時使用v-if(實際上這在Vue3 中是錯誤的寫法)

  • v-once
  • v-memo

    #:不再變化的資料使用v-once;按條件跳過更新時使用v-memo

  • #長列表效能最佳化:如果是大數據長列表,可採用虛擬滾動,只渲染一小部分區域的內容。一些開源程式庫(vue-virtual-scroller /

    vue-virtual-scroll-grid
  • ##事件的銷毀:Vue元件銷毀時,會自動解綁它的全部指令以及事件監聽器,但是僅限於元件本身的事件。
  • 圖片懶加載,自訂v-lazy

    指令(參考項目:
  • vue-lazyload

第三方外掛程式按需引入

element-plus 避免體積太大

  • #子元件分割策略:較重的狀態元件適合分割

  • SSR

    服務端渲染解決首屏渲染慢的問題
  • 6. 刷新後Vuex 狀態遺失怎麼解決?
  • 想法:

為什麼刷新後 Vuex 狀態為什麼會遺失?
  • 解決方法
  • 第三方函式庫以及原理探討##個人理解

  • ##回答:

  • 因為Vuex 只是在記憶體中儲存狀態,刷新後就會遺失,如果要持久化就要存起來。 可以是用localStorage 儲存Vuex 的狀態,store 中把值取出來當作state 的初始值,提交mutation 的時候就存入localStorage

可以用

vuex-persistvuex-persistedstate

這個插件,可以透過插件選項控制哪些需要持久化。內部的原則就是透過訂閱

mutation 變化做統一處理。

這裡有兩個問題,一是如果使用者手動改了

localStorage怎麼辦?那我 Vuex

裡的狀態不是也改變了?第二是因為

localStorage API 的原因只能儲存字串,所以我們只能將資料透過JSON.stringify

轉換為字串,而當我們儲存的資料為
    Map
  • Set

  • Function
  • 這種引用型別的資料時,

    JSON.stringify

    轉換後會變味
  • {}
  • 而丟失。

  • 對應第一個問題我的解決方法是可以透過監聽

    storage

    事件來清除資料
  • window.addEventListener("storage", function () {
        localStorage.clear();
        window.location.href = &#39;/login&#39;
        console.error("不要修改localStorage的值~~~");
    });
    登入後複製
對於第二個問題沒辦法了,只能選擇不適用

MapSet

這種引用類型。
  • 7. Vue3 為什麼用Proxy 取代defineProperty ?#思路:##屬性攔截的幾種方式

    #########defineProperty的問題#############Proxy的優點############其他考慮##############################################################。 ############回答:###################JS### 中做屬性攔截常見的方式有三種:###defineProperty ###、###getter/setters### 和###Proxy######
  • Vue2 中使用 defineProperty 的原因是, 2013 年只能使用这种方式,由于该 API 存在一些局限性,比如对于数组的拦截有问题,为此 Vue 需要专门为数组响应式做一套实现。另外不能拦截那些新增、删除属性;最后 defineProperty 方案在初始化时需要深度递归遍历处理对象才能对它进行完全拦截,明显增加了初始化的时间。

  • 以上两点在 Proxy 出现后迎刃而解,不仅可以对数组实现拦截,还能对 MapSet 实现拦截;另外 Proxy 的拦截也是懒处理行为,如果用户没有访问嵌套对象,那么也不会实施拦截,这就让初始化的速度和内存占用改善了。

  • Proxy 有兼容性问题,完全不支持IE

8. 怎么实现路由懒加载?

思路:

  • 必要性

  • 何时用

  • 怎么用

  • 使用细节

回答:

  • 当打包构建时,Javascript 抱回变得非常大,影响页面加载。利用路由懒加载我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应最贱,这样更加高效,是一种优化手段。

  • 一般来说,对于所有的路由都使用动态导入是个好主意

  • component 选项配置一个返回 Promise组件的函数就可以定义懒加载路由.例如:

{
  path: &#39;/login&#39;,
  component: () => import(&#39;../views/login/Login.vue&#39;)
},
登入後複製
  • 结合注释

{
  path: &#39;/login&#39;,
  component: () => import(/* webpackChunkName: "login" */&#39;../views/login/Login.vue&#39;)
},
登入後複製

vite中结合rollupOptions定义分块 5. 路由中不能使用异步组件

9. history模式 和 hash 模式有何区别?

  • Vue-Router 有三个模式,其中 history 和 hash 更为常用。两者差别主要在显示形式和部署上,

  • hash模式在地址栏现实的时候有一个 #,这种方式使用和部署都较简单;history模式url看起来更优雅没关,但是应用在部署时需要做特殊配置,web服务器需要做回退处理,否则会出现刷新页面404的问题。

  • 在实现上 hash模式是监听hashchange事件触发路由跳转,history模式是监听popstate 事件触发路由跳转。

10. 说说 nextTick 的使用和原理?

  • VuenextTick 是等待下一次 DOM 更新刷新的工具方法。

  • Vue 有一个异步更新策略,意思是如果数据变化,Vue 不会立刻更新 DOM,而是开启一个队列,把组件更新函数保存在队列中,在同一时间循环中发生的所有数据变更会异步的批量更新。这一策略导致我们对数据的修改不会立刻体现在 DOM 上,此时如果想要获取更新后的 DOM 状态,就需要使用 nextTicknextTick 接受一个函数,我们可以在这个函数内部访问最新的 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-forv-if 放在一起, 怎么解决呢?一是可以定义一个计算属性,让 v-for 遍历计算属性。二是可以把 if 移到内部容器里(ul ol)或者把v-for移植外部容器(template)中

vue2文件vue3文件

#12. 如何監聽 Vuex 狀態變更?

  • watch

  • store.subscribe()

watch 方式,可以以字串形式監聽$store.state.xx; subscribe 方法參數是一個回呼函數,回呼函數接受mutation 物件和state 對象,可以透過mutation.type 判斷監聽的目標。 wtach 方法更簡單好用, subscribe 會略繁瑣,一般用vuex 插件中(可以提一下vuex的持久化插件vuex-persistvuex-persistedstate

13. 你覺得Vuex 有什麼缺點?

  • 不支援持久化,頁面刷新狀態就會遺失

  • 使用模組比較繁瑣

  • #不支援ts (或很不友善)

vue3 pinia 會是更好的組合。

14. ref 和reactive 異同點?

  • #兩者都能傳回響應式對象,ref 傳回的是一個響應式Ref 對象, reactive 傳回的是響應式代理對象。

  • ref 通常是處理單一值得響應式,reactive 用於處理物件類型的資料響應式

  • ref 需要透過.value 訪問, 在視圖中會自動脫ref,不需要.valueref 可以接收物件或陣列但內部仍然是reactive 實現的;reactive 如果接收Ref 物件會自動脫ref ;使用展開運算子展開reactive 傳回的響應式物件會使其失去回應性,可以結合toRefs()將值轉換為Ref 物件後再展開。

  • reactive 內部使用 Prxoy# 代理攔截物件各種操作,而ref 內部封裝一個RefImpl 類,設定get value/set value,攔截使用者對值得存取。

16. Vue 中如何擴充一個元件?

  • 邏輯擴充:mixinsextendscomposition 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 中要解決的一個核心問題就是連接資料層和視圖層,透過資料變化驅動視圖更新,要做到這點就需要對資料做響應式處理。

  • 透過資料響應式加上虛擬

    DOMpatch 演算法,我們只需要操作數據,關心業務,完全不需要接觸繁瑣的DOM 操作,打打提升了開發效率,降低開發難度。

  • vue2 中實作資料回應式的核心是透過Object.defineProperty() 方法對資料進行攔截,當get 資料時做依賴收集set 資料時做更新通知。這種機制很好的及絕了資料響應式的問題,但是實際使用也存在缺點,例如在初始化時的遞歸遍歷會造成效能損失;無法監聽新增或刪除屬性,在vue 中要透過像Vue.set/delete 這種特定的API 才能實現對物件陣列屬性的新增和刪除,而且也不支援MaSet這些資料結構,

  • #為了解決這些問題,

    Vue3 重寫了這部分實現,利用的是ES6 中的Proxy 代理要回應化的資料。它有很多好處,初始化效能和記憶體都大幅改善,也不需要特殊的 API ,但不支援 IE 瀏覽器。

21. 從template 到render 做了什麼

#問

templaterender 的過程其實是問的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

    鉤子或beforeRouteEntervue-router 的一個守衛)

  • keep-alive

    是一個通用元件,它內部定義了一個map,快取創建過的元件實例,它傳回的渲染函數內部會尋找內嵌的component 元件對應元件的vnode ,如果改組件在map中存在就直接回傳它。由於componentis 屬性是一個響應式數據,因此只要它變化,keep-aliverender 函數就會重新執行。 </li></ul><h2><strong>23. 虛擬DOM</strong></h2><ul style="list-style-type: disc;"><li><p>#虛擬 <code>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 不行。

  • 計算屬性傳遞一個物件有setget 兩個選項,是它稱為即可讀又可寫的計算屬性,如果傳遞的是函數的話預設就是get 選項,watch 可以傳遞一個對象,設定deep、immediate等選項

  • vue3watch 發生了一些變化,例如不能再偵測一個點操符之外的字串表達式,reactivity API 中新出的 watchwatchEffect 可以完全取代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 视图中农每个依赖均有更新函数对应,可以做到精确更新,因此不需要 虚拟DOMpatching 算法支持,但是这样粒度过细导致 Vue1.x 无法承载较大应用;Vue2.x 中为了降低 Watcher 粒度,每个组件只有一个 Watcher 与之对应,此时就需要引入 patching 算法才能精确找到发生变化的地方并高效更新。

  • vuediff 执行的时刻是组件内响应式数据变更触发实例执行其更新函数时,更新函数会再次执行 render函数 获得最新的 虚拟DOM ,然后执行 patch函数对比新旧虚拟DOM,将其转化为对应的 DOM 操作。

  • patch 过程是一个递归过程,遵循深度优先、同层比较的策略;以 vue3patch 为例:

    • 首先判断两个节点是否为相同同类节点,不同则删除重新创建
    • 如果双方都是文本则更新文本内容
    • 如果双方都是元素节点则递归更新子元素,同时更新元素属性
    • 更新子节点时又分了几种情况:
      • 新的子节点是文本,老的子节点是数组则清空,并设置文本;
      • 新的子节点是文本,老的子节点是文本则直接更新文本;
      • 新的子节点是数组,老的子节点是文本则清空文本,并创建新子节点数组中的子元素;
      • 新的子节点是数组,老的子节点也是数组,那么比较两组子节点,更新细节blabla
  • vue3 中引入的更新策略:编译期优化 patchFlagsblock

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-linkrouter-view,分别实现页面跳转和内容显示
    • 定义两个全局变量:$router$route,组件内可以访问当前路由和路由器实例

31. 什么情况需要使用Vuex模块?

  • 在项目规模变大的之后,单独一个store对象会过于庞大臃肿,此时通过模块方式可以拆分来便于维护

  • 可以按之前规则单独编写资规模代码,然后在主文件中通过 modules 选项组织起来:createStore({modules: {...}})

  • 使用時需要注意存取子模組狀態時需要加上註冊模組名稱。但同時gettersmutationsactions又在全域空間中,使用方式和之前一樣。如果要做到完全拆分,需要在子模組加上 namespace選項,此時再訪問它們就要加上命名空間前綴。

  • 模組的方式可以分割程式碼,但是缺點也很明顯,使用起來比較繁瑣,容易出錯,而且類型系統支援很差,不能給我們帶來幫助。 pinia 顯然在這方面有了很大改進,是時候切換過去了。

32. vue 元件為什麼只能有1個根節點

  • vue2 中元件確實只能有一個跟,但vue3 中元件已經可以多根元件了。

  • 之所以需要這樣是因為vdom 是一顆單根樹狀結構,patch 方法在遍歷的時候從根節點開始遍歷,它要求只有一個根節點。元件也會轉換為一個 vdom,自然應該滿足這個要求。

  • vue3 中之所以可以寫多個根節點,是因為引入了Fragment 的概念,這是一個抽象的節點,如果發現元件時多根的,就建立一個Fragment 節點,把多個根節點當作它的children。將來 pathch 的時候,如果發現是一個 Fragment 節點,則直接遍歷 children 建立或更新。

33. v-once 使用場景有哪些?

  • v-oncevue 的內建指令,作用是只渲染指定元件或元素一次,並跳過未來對其更新。

  • 如果我們有一些元素或元件再初始化渲染之後不再需要變化,這種情況下適合使用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

  • keyvuepatch 過程中判斷兩個節點是否為相同節點的關鍵條件(另一個是元素類型),如果不設定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. 什麼是遞迴元件?使用場景有哪些?

  • 如果某個元件透過元件名稱來引用它自己,這種情況就是遞迴元件。

  • 類似TreeMenu 這類元件,它們的節點往往包含子節點,子節點結構和父節點往往是相同的。這類組件的資料往往也是樹狀結構,這種都是使用遞迴元件的典型場景。

42. 你寫過自訂指令嗎?

使用自訂指令分為定義、註冊、和使用

  • #定義有兩種方式,物件和函數形式,前者類似元件定義,有各種生命週期;後者只會在mountedupdated 時執行

  • 註冊:可以使用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>)

##此外,Vue3在框架層級也有很多兩點和改進

  • 更快
    • 虛擬DOM 重寫
    • #編譯器最佳化:靜態提升、patchFlagsblock
    • 基於Proxy 的響應式系統
  • #更小:更好的搖樹優化
  • #更容易維護:TS 模組化
  • 更容易擴展
    • 獨立的響應化模組
    • #自訂渲染器

##44. Vue3設計目標和最佳化點

最大設計目標就是替代

Vue2,為了實現這一點,Vue3 在以下幾個方面做了很大改進,如:易用性,框架性能、擴展性、可維護性、開發體驗等

  • #易用性方面:主要有

    API 簡化v-model 變成了v-modelsync 修飾符的結合體。類似的還有 h(type,props,children) 函數中的 props 不用考慮區分屬性、特性、事件等,框架替我們判斷,易用性增。

  • 開發體驗方面:新組成

    Teleport Fragment Suspense 等都會簡化特定場景的程式碼編寫。 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 APImixins 的各種缺點(會衝突很混亂);另外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對外暴露狀態,提供commitdispatch 修改屬性。這裡需要設定 state 為響應式對象,同時將 Store 定義為一個 Vue 外掛(install方法)。

commit 可以取得使用者傳入mutations  並執行它,這樣可以依照使用者提供的方法修改狀態,dispatch 類似,但dispatch 需要傳回一個Promise 給使用者用於處理非同步結果。

(學習影片分享:vuejs入門教學程式設計基礎影片

以上是【整理總結】45+個Vue面試題,帶你鞏固知識點!的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:juejin.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
最新問題
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板