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 進行數據管理