「2022」打算跳槽漲薪,必問面試題及答案 —— VUE篇
1、為什麼選擇VUE,解決了什麼問題?
vue.js 正如官網所說的,是一套構建使用者介面的漸進式框架。與其它重量級框架不同的是,vue 被設計為可以自底向上逐層應用。vue 的核心庫只關注檢視層,不僅易於上手,還便於與第三方庫或既有專案整合。另外一方面,當與現代化工具鏈以及各種支援類庫結合使用時,vue 也完全能夠為複雜的單頁應用提供驅動。
vue.js 有宣告式,響應式的資料繫結,元件化開發,並且還使用虛擬 DOM 等技術,統一程式設計規範和模組等,將專案功能模組化更方便組織和構建複雜應用,便於專案的擴充套件和維護。vue 框架維護及時,且 Vue 3 將在2022 年 2 月 7 日成為新的預設版本。
2、如果加入 keep-alive,第一次進入元件會執行哪些生命週期函式?
會執行的鉤子函式以及它們的順序分別為:
beforeCreat、created、beforeMount、mounted、activated
3、key 的作用和工作原理。
key 的作用主要是為了高效地更新虛擬 DOM,其原理是 vue 中在 patch 過程中,通過 key 可以精準判斷兩個節點是否是同一個,從而避免頻繁更新不同元素,使得整個 patch 過程更加高效,減少 DOM 操作量,提高效能。
另外,若不設定 key 還可能在列表更新時,引發一些隱蔽的 bug 。vue 在使用相同標籤名元素的過濾或切換時,也會使用到 key 屬性,其目的也是為了讓 vue 可以區分它們,否則 vue 只會替換其內部屬性而不會觸發過濾效果。
4、v-if 和 v-for 的優先順序哪個高?
v-for 的優先順序更高。
如果 v-if 和 v-for 同時出現,每次渲染都會先執行迴圈,再判斷條件,無論如何迴圈都不可避免,浪費了效能。
情景一:每次遍歷時,都需要執行 v-if 解析一次,浪費效能。
<ul> <li v-for="user in users" v-if="shouldShowUsers" :key="user.id" > {{ user.name }} </li> </ul>
要避免出現這種情況,則在外層巢狀 template ,在這一層進行 v-if 判斷,然後再內部進行 v-for 迴圈。可以改為:
<ul> <template v-if="shouldShowUsers"> <li v-for="user in users" :key="user.id" > {{ user.name }} </li> </template> </ul>
情景二:v-if 和 v-for 同時出現在一個標籤,過濾一個列表中的專案,比如:
<ul> <li v-for="user in users" v-if="user.isActive" :key="user.id" > {{ user.name }} </li> </ul>
在這種情況下,請將 users 替換為一個計算屬性,讓其返回過濾後的列表。
<ul> <li v-for="user in activeUsers" :key="user.id" > {{ user.name }} </li> </ul> computed: { activeUsers: function () { return this.users.filter(function (user) { return user.isActive }) } }
5、談談對 vue 元件化的理解。
5.1、元件化的定義
元件是獨立和可複用的程式碼組織單元,組價系統是 vue 核心特性之一,它使開發者使用小型、獨立和通常可複用的元件構建大型應用。
也可以通俗介紹,把一些使用者在程式中一些獨立的功能和模組單獨提取出來,然後切分為更小的塊,這些塊有獨立的邏輯,有更好的複用性。
元件按照分類有:頁面元件(導航)、業務元件(登入)、通用元件(輸入框)。
5.2、元件化特點
vue 的元件是基於配置的,通常編寫的元件是元件配置而非元件,框架後續會生成其建構函式,它們基於 VueComponent 這個類擴充套件於 vue 。
常見的元件化技術有:prop 屬性、自定義事件、插槽等,這些主要用於元件之間的通訊等。
元件之間遵循單向資料流原則。
5.3、元件化的優點
元件化的開發能大幅提高開發效率、測試性和複用性等。
合理的劃分元件能夠大幅提升應用效能,元件應該是高內聚,低耦合的。
6、為什麼 data 在元件內必須是函式,而 vue 的根例項則沒有此限制?
vue 元件可能存在多個例項,如果使用物件形式定義 data ,則會導致它們公用一個 data 物件,那麼狀態變更將會影響所有元件例項,這是不合理的。
如果採用函式的形式,在例項化元件時,data 會被當做工廠函式返回一個全新的 data 物件,有效規避多例項之間狀態汙染問題。
所以在元件中的 data 必須是函式,不能使用物件形式。那為什麼 vue 根例項沒有限制呢?
在 vue 中根例項只能有一個,所以不需要擔心多例項的問題,所以根例項中的 data 可以是函式也可以是物件。
7、你瞭解哪些 vue 效能優化的方法?
我所瞭解的 vue 效能優化方法分別有:
1>、路由懶載入
Vue.use(VueRouter) // 傳統寫法 import Home from '@/views/login/index.vue' //路由懶載入 const Login = ()=> import('@/views/login/index.vue') const router = new VueRouter({ routes: [ { path: '/login', component: Login }, { path: '/home', component: Home }, ] export default router
使用路由懶載入,專案打包的時候體積會大幅減小,訪問專案時,這些元件也會按需進行載入,大大提升了專案效能。
2>、keep-alive 快取頁面
<template> <keep-alive> <router-view /> </keep-alive> </template>
使用 keep-alive 之後會快取頁面,第一次載入之後,關閉再次開啟,頁面不會重新渲染。keep-alive 的屬性:
- include:字串或正則表示式。如果只快取個別頁面,可以使用 include 屬性,只快取匹配元件。
- exclude:字串或正則表示式。如果個別頁面不需要快取時,可以使用 exclude 屬性,任何匹配的元件都不會快取。
3>、v-for遍歷避免同時使用 v-if
<ul> <li v-for="user in activeUsers" :key="user.id" > {{ user.name }} </li> </ul> computed: { activeUsers: function () { return this.users.filter(function (user) { return user.isActive }) } }
4>、長列表效能優化
如果列表是純粹的資料展示,不會有任何的改變,就不需要做響應式。
export default{ data(){ return { users:[] } }, created(){ const user = await axios("/api/user") this.users = Object.freeze(user) } }
Object.freeze() 方法可以凍結一個物件,物件被凍結之後不能被修改,可以讓效能大幅度提升。
如果是大資料長列表,可採用虛擬滾動,只渲染少部分割槽域的內容。可採用三方 vue-virtual-scroll。
5>、事件的銷燬
vue元件銷燬時,會自動解綁它的全部指令及事件監聽器,但是僅限於元件本身的事件。
created(){ this.timer = setInterval( this.refresh, 2000 ) }, beforeDestory(){ clearInterval( this.timer ) }
6>、圖片懶載入
對於圖片過多的頁面,為了加快頁面的載入速度,所以很多時候,需要把未出現在可視區域的圖片暫不進行載入,滾動到可視區域之後再開始載入。
可以使用三方的 vue-lazyload 庫。
<img v-lazy="/src/img/01.jpg" />
7>、第三方外掛按需引用
使用三方庫時,可以按需引入避免體積太大。比如 element-ui :
import { Button } from "element-ui"
8>、無狀態的元件標記為函式式元件
<template functional> <div>元件內容</div> </template>
通過 functional 將元件標記為函式式元件,因為函式式元件沒有例項,所以執行時耗費資源較少。
另外還有 v-show 複用 DOM、子元件分割、SSR 等。
8、computed 與 methods 、watch 的區別?
computed VS methods
computed:{ yyds(){ log("computed show") return "計算屬性" } }, methods:{ show(){ log("method show") return "計算屬性" } }
computed 是計算屬性,methods 內都是方法,所以呼叫不同分別為:
<div>yyds</div>
<div>show()</div>
computed 是有快取的,而 methods 沒有快取,所以 computed 效能比 methods 的好。
computed VS watch
computed 是計算某一個屬性的改變,如果某一個值改變了,計算屬性會監測到,然後進行返回值。
watch 是監聽某一個數據或路由,改變了才會響應,只有改變了才會執行操作。
9、你怎麼理解 vue 中的 diff 演算法?
1.diff演算法是虛擬DOM技術的必然產物:通過新舊虛擬DOM作對比(即diff),將變化的地方更新在真實DOM上;
另外,也需要diff高效的執行對比過程,從而降低時間複雜度為O(n)。(what)
2.vue2.x中為了降低Watcher粒度,每個元件只有一個Watcher與之對應,只有引入diff才能精確找到發生變化的地方。(why)
3.vue中diff執行的時刻是元件例項執行其更新函式時,它會比對上一次渲染結果oldVnode和新的渲染結果newVnode,此過程稱為patch。(where)
4.diff過程整體遵循深度優先、同層比較的策略;兩個節點之間比較會根據它們是否擁有子節點或者文字節點做不同操作;(How)
比較兩組子節點是演算法的重點,首先假設頭尾節點可能相同做4次比對嘗試,如果沒有找到相同節點才按照通用方式遍歷查詢,查詢結束再按情況處理剩下的節點;
藉助key通常可以非常精確找到相同節點,因此整個patch過程非常高效。
10、props 和 data 的優先順序誰高?
vue元件內資料相關的屬性它們的樣式優先順序從高到底分別為:
props > methods > data > computed > watch
11、vue 元件之間的通訊
vue 元件之間的關係有:父子關係、兄弟關係、隔代關係。
所以 vue 元件之間的通訊可分為:父子元件之間通訊,兄弟元件之間通訊和跨層元件之間通訊。
1>、父傳子
可使用的方法有:
- 通過 props 傳值
- 通過 refs 傳值
- 通過 children 傳值
2>、子傳父
可使用的方法:
- $emit 自定義事件
- provide 和 inject
3>、兄弟元件之間
- 利用中央事件匯流排 bus 的 $emit 和 $on 。
- 笨辦法,通過父元件共同傳值
4>、跨層元件
- provide 和 inject
5>、沒有關係的元件之間通訊
- 可以使用 vuex 進行資料管理