2021 Vue.js 面試題匯總及答案


1. 基本問題

1.1. Vue.js 的特點

  • 易用: 簡單,易學,上手快
  • 靈活: (漸進式)不斷繁榮的生態系統,可以在一個庫和一套完整框架之間自如伸縮。
  • 高效: 20kB min+gzip 運行大小;超快虛擬 DOM;最省心的優化
  • 雙向綁定:開發效率高
  • 基於組件的代碼共享
  • Web項目工程化,增加可讀性、可維護性

1.2. Vue.js 雙向綁定的原理

Vue.js 2.0 采用數據劫持(Proxy 模式)結合發布者-訂閱者模式(PubSub 模式)的方式,通過 Object.defineProperty()來劫持各個屬性的 setter,getter,在數據變動時發布消息給訂閱者,觸發相應的監聽回調。

每個組件實例都有相應的watcher程序實例,它會在組件渲染的過程中把屬性記錄為依賴,之后當依賴項的setter被調用時,會通知watcher重新計算,從而致使它關聯的組件得以更新。

Vue.js 3.0, 放棄了Object.defineProperty ,使用更快的ES6原生 Proxy (訪問對象攔截器, 也稱代理器)

步驟:

  1. 需要observe的數據對象進行遞歸遍歷,包括子屬性對象的屬性,都加上setter和getter這樣的話,給這個對象的某個值賦值,就會觸發setter,那么就能監聽到了數據變化

  2. compile解析模板指令,將模板中的變量替換成數據,然后初始化渲染頁面視圖,並將每個指令對應的節點綁定更新函數,添加監聽數據的訂閱者,一旦數據有變動,收到通知,更新視圖

  3. Watcher訂閱者是Observer和Compile之間通信的橋梁,主要做的事情是: ①在自身實例化時往屬性訂閱器(dep)里面添加自己 ②自身必須有一個update()方法 ③待屬性變動dep.notice()通知時,能調用自身的update()方法,並觸發Compile中綁定的回調,則功成身退。

  4. MVVM作為數據綁定的入口,整合Observer、Compile和Watcher三者,通過Observer來監聽自己的model數據變化,通過Compile來解析編譯模板指令,最終利用Watcher搭起Observer和Compile之間的通信橋梁,達到數據變化 -> 視圖更新;視圖交互變化(input) -> 數據model變更的雙向綁定效果。

1.3. Vue.js 3.0 放棄defineProperty, 使用Proxy的原因

Object.defineProperty缺陷

  1. 監控到數組下標的變化時,開銷很大。所以Vue.js放棄了下標變化的檢測;
  2. Object.defineProperty只能劫持對象的屬性,而Proxy是直接代理對象。Object.defineProperty需要遍歷對象的每個屬性,如果屬性值也是對象,則需要深度遍歷。而 Proxy 直接代理對象,不需要遍歷操作。
  3. Object.defineProperty對新增屬性需要手動進行Observe。vue2時需要使用 vm.$set 才能保證新增的屬性也是響應式
  4. Proxy支持13種攔截操作,這是defineProperty所不具有的
  5. Proxy 作為新標准,長遠來看,JS引擎會繼續優化 Proxy,但 getter 和 setter 基本不會再有針對性優化

1.4. Vue 2 中給 data 中的對象屬性添加一個新的屬性時會發生什么?如何解決?

視圖並未刷新。這是因為在Vue實例創建時,新屬性並未聲明,因此就沒有被Vue轉換為響應式的屬性,自然就不會觸發視圖的更新,這時就需要使用Vue的全局 api $set():this.$set(this.obj, 'new_property', 'new_value')

1.5. Computed和Watch的區別

  1. computed 計算屬性 : 依賴其它屬性值,並且 computed 的值有緩存,只有它依賴的 屬性值發生改變,下一次獲取 computed 的值時才會重新計算 computed 的值。
  2. watch 偵聽器 : 更多的是觀察的作用,無緩存性,類似於某些數據的監聽回調,每 當監聽的數據變化時都會執行回調進行后續操作。

運用場景:

  1. 當我們需要進行數值計算,並且依賴於其它數據時,應該使用 computed,因為可以利用 computed 的緩存特性,避免每次獲取值時,都要重新計算。
  2. 當我們需要在數據變化時執行異步或開銷較大的操作時,應該使用 watch,使用 watch 選項允許我們執行異步操作 ( 訪問一個 API ),限制我們執行該操作的頻率, 並在我們得到最終結果前,設置中間狀態。這些都是計算屬性無法做到的。
  3. 多個因素影響一個顯示,用Computed;一個因素的變化影響多個其他因素、顯示,用Watch;

1.6. Computed 和 Methods 的區別

  1. computed: 計算屬性是基於它們的依賴進行緩存的,只有在它的相關依賴發生改變時才會重新求值對於 method ,只要發生重新渲染,
  2. method 調用總會執行該函數

1.7. 虛擬DOM,diff算法

(1)讓我們不用直接操作DOM元素,只操作數據便可以重新渲染頁面
(2)虛擬dom是為了解決瀏覽器性能問題而被設計出來的
當操作數據時,將改變的dom元素緩存起來,都計算完后再通過比較映射到真實的dom樹上
(3)diff算法比較新舊虛擬dom。如果節點類型相同,則比較數據,修改數據;如果節點不同,直接干掉節點及所有子節點,插入新的節點;如果給每個節點都設置了唯一的key,就可以准確的找到需要改變的內容,否則就會出現修改一個地方導致其他地方都改變的情況。比如A-B-C-D, 我要插入新節點A-B-M-C-D,實際上改變的了C和D。但是設置了key,就可以准確的找到B C並插入

1.8. 為何需要Virtual DOM?

  1. 具備跨平台的優勢
  2. 操作 DOM 慢,js運行效率高。我們可以將DOM對比操作放在JS層,提高效率。
  3. 提升渲染性能

1.9. 過濾器 (Filter)

在Vue中使用filters來過濾(格式化)數據,filters不會修改數據,而是過濾(格式化)數據,改變用戶看到的輸出(計算屬性 computed ,方法 methods 都是通過修改數據來處理數據格式的輸出顯示。
使用場景: 比如需要處理時間、數字等的的顯示格式;

1.10. 常見的事件修飾符及其作用

  1. .stop:等同於 JavaScript 中的 event.stopPropagation() ,防止事件冒泡;
  2. .prevent :等同於 JavaScript 中的 event.preventDefault() ,防止執行預設的行為(如果事件可取消,則取消該事件,而不停止事件的進一步傳播);
  3. .capture :當元素發生冒泡時,先觸發帶有該修飾符的元素。若有多個該修飾符,則由外而內觸發。如 div1中嵌套div2中嵌套div3.capture中嵌套div4,那么執行順序為:div3=》div4=》div2=》div1
  4. .self :只會觸發自己范圍內的事件,不包含子元素;
  5. .once :只會觸發一次。

1.11. v-show指令和v-if指令的區別是什么?

v-show 僅僅控制元素的顯示方式,將 display 屬性在 block 和 none 來回切換;而v-if會控制這個 DOM 節點的存在與否。當我們需要經常切換某個元素的顯示/隱藏時,使用v-show會更加節省性能上的開銷;當只需要一次顯示或隱藏時,使用v-if更加合理。

1.12. v-model 是如何實現的,語法糖實際是什么

  1. 作用在表單元素上v-model="message"等同於v-bind:value="message" v-on:input="message=$event.target.value"
  2. 作用在組件上, 本質是一個父子組件通信的語法糖,通過prop和$.emit實現, 等同於:value="message" @input=" $emit('input', $event.target.value)"

1.13. data為什么是一個函數而不是對象

JavaScript中的對象是引用類型的數據,當多個實例引用同一個對象時,只要一個實例對這個對象進行操作,其他實例中的數據也會發生變化。

而在Vue中,我們更多的是想要復用組件,那就需要每個組件都有自己的數據,這樣組件之間才不會相互干擾。

所以組件的數據不能寫成對象的形式,而是要寫成函數的形式。數據以函數返回值的形式定義,這樣當我們每次復用組件的時候,就會返回一個新的data,也就是說每個組件都有自己的私有數據空間,它們各自維護自己的數據,不會干擾其他組件的正常運行。

1.14. Vue template 到 render 的過程

  1. 調用parse方法將template轉化為ast(抽象語法樹, abstract syntax tree)
  2. 對靜態節點做優化。如果為靜態節點,他們生成的DOM永遠不會改變,這對運行時模板更新起到了極大的優化作用。
  3. 生成渲染函數. 渲染的返回值是VNode,VNode是Vue的虛擬DOM節點,里面有(標簽名,子節點,文本等等)

1.15. Vue data 中某一個屬性的值發生改變后,視圖會立即同步執行重新渲染嗎?

不會立即同步執行重新渲染。
Vue 實現響應式並不是數據發生變化之后 DOM 立即變化,而是按一定的策略進行 DOM 的更新。
Vue 在更新 DOM 時是異步執行的。只要偵聽到數據變化, Vue 將開啟一個隊列,並緩沖在同一事件循環中發生的所有數據變更。

如果同一個watcher被多次觸發,只會被推入到隊列中一次。這種在緩沖時去除重復數據對於避免不必要的計算和 DOM 操作是非常重要的。
然后,在下一個的事件循環"tick"中,Vue 刷新隊列並執行實際(已去重的)工作。

1.16. axios是什么

易用、簡潔且高效的http庫, 支持node端和瀏覽器端,支持Promise,支持攔截器等高級配置。

1.17. sass是什么?如何在vue中安裝和使用?

sass是一種CSS預編譯語言安裝和使用步驟如下。

  1. 用npm安裝加載程序( sass-loader、 css-loader等加載程序)。
  2. 在 webpack.config.js中配置sass加載程序。

1.18. Vue.js頁面閃爍

Vue. js提供了一個v-cloak指令,該指令一直保持在元素上,直到關聯實例結束編譯。當和CSS一起使用時,這個指令可以隱藏未編譯的標簽,直到實例編譯結束。用法如下。

[v-cloak]{ 
 display:none; 
} 
<div v-cloak>{{ title }}</div>

1.19. 如何解決數據層級結構太深的問題

在開發業務時,經常會岀現異步獲取數據的情況,有時數據層次比較深,如以下代碼: span 'v-text="a.b.c.d"></span>, 可以使用vm.$set手動定義一層數據: vm.$set("demo",a.b.c.d)

1.20. 在 Vue. js開發環境下調用API接口,如何避免跨域

config/ index.js內對 proxyTable項配置代理。

1.21. 批量異步更新策略

Vue 在修改數據后,視圖不會立刻更新,而是等同一事件循環中的所有數據變化完成之后,再統一進行視圖更新。
換句話說,只要觀察到數據變化,就會自動開啟一個隊列,並緩沖在同一個事件循環中發生的所以數據改變。在緩沖時會去除重復數據,從而避免不必要的計算和 DOM 操作。

1.22. vue 的 nextTick 方法的實現原理

  1. vue 用異步隊列的方式來控制 DOM 更新和 nextTick 回調先后執行
  2. microtask 因為其高優先級特性,能確保隊列中的微任務在一次事件循環前被執行完畢

1.23. Vue 組件 data 為什么必須是函數 ?

因為組件是可以復用的,JS 里對象是引用關系,如果組件 data 是一個對象,那么子組件中的 data 屬性值會互相污染。
所以一個組件的 data 選項必須是一個函數,因此每個實例可以維護一份被返回對象的獨立的拷貝。

1.24. v-if和v-for一起使用的弊端及解決辦法

由於v-for的優先級比v-if高,所以導致每循環一次就會去v-if一次,而v-if是通過創建和銷毀dom元素來控制元素的顯示與隱藏,所以就會不停的去創建和銷毀元素,造成頁面卡頓,性能下降。

解決辦法:

  1. 在v-for的外層或內層包裹一個元素來使用v-if
  2. 用computed處理

1.25. vue常用指令

  1. v-model 多用於表單元素實現雙向數據綁定(同angular中的ng-model)
  2. v-bind 動態綁定 作用: 及時對頁面的數據進行更改
  3. v-on:click 給標簽綁定函數,可以縮寫為@,例如綁定一個點擊函數 函數必須寫在methods里面
  4. v-for 格式: v-for="字段名 in(of) 數組json" 循環數組或json(同angular中的ng-repeat)
  5. v-show 顯示內容 (同angular中的ng-show)
  6. v-hide 隱藏內容(同angular中的ng-hide)
  7. v-if 顯示與隱藏 (dom元素的刪除添加 同angular中的ng-if 默認值為false)
  8. v-else-if 必須和v-if連用
  9. v-else 必須和v-if連用 不能單獨使用 否則報錯 模板編譯錯誤
  10. v-text 解析文本
  11. v-html 解析html標簽
  12. v-bind:class 三種綁定方法 1、對象型 '{red:isred}' 2、三元型 'isred?"red":"blue"' 3、數組型 '[{red:"isred"},{blue:"isblue"}]'
  13. v-once 進入頁面時 只渲染一次 不在進行渲染
  14. v-cloak 防止閃爍
  15. v-pre 把標簽內部的元素原位輸出

1.26. 組件傳值方式有哪些

  1. 父傳子:子組件通過props['xx'] 來接收父組件傳遞的屬性 xx 的值
  2. 子傳父:子組件通過 this.$emit('fnName',value) 來傳遞,父組件通過接收 fnName 事件方法來接收回調
  3. 其他方式:通過創建一個bus,進行傳值
  4. 使用Vuex

1.27. vue-loader是什么?使用它的用途有哪些?

2. 組件 Component

2.1. vue中如何編寫可復用的組件 (編寫組件的原則)

  1. 以組件功能命名
  2. 只負責ui的展示和交互動畫,不要在組件里與服務器打交道(獲取異步數據等)
  3. 可復用組件不會因組件使用的位置、場景而變化。盡量減少對外部條件的依賴。

2.2. 如何讓CSS只在當前組件中起作用?

在每一個Vue.js組件中都可以定義各自的CSS、 JavaScript代碼。如果希望組件內寫的CSS只對當前組件起作用,只需要在Style標簽添加Scoped屬性,即

2.3. keep-alive是什么?

如果需要在組件切換的時候,保存一些組件的狀態防止多次渲染,就可以使用 keep-alive 組件包裹需要保存的組件。

兩個重要屬性,include 緩存組件名稱,exclude 不需要緩存的組件名稱。

2.4. 如何在 Vue. js動態插入圖片

對“src”屬性插值將導致404請求錯誤。應使用 v-bind:src (簡寫:src)格式代替。

2.5. 父子組件的生命周期順序

  1. 加載渲染過程:
    父beforeCreate->父created->父beforeMount->子beforeCreate->子created->子beforeMount->子mounted->父mounted
  2. 子組件更新過程:父beforeUpdate->子beforeUpdate->子updated->父updated
  3. 父組件更新過程:父beforeUpdate->父updated
  4. 銷毀過程:父beforeDestroy->子beforeDestroy->子destroyed->父destroyed

3. Vuex

3.1. vuex的核心概念

  1. state => 基本數據
  2. getters => 從基本數據派生的數據
  3. mutations => 修改數據,同步
  4. actions => 修改數據,異步 (Action 提交的是 mutation,而不是直接變更狀態)
  5. modules => 模塊化Vuex

3.2. vuex是什么?怎么使用?哪種功能場景使用它?

Vuex 是一個專為 Vue.js 應用程序開發的狀態管理器,采用集中式存儲管理應用的所有組件的狀態,主要是為了多頁面、多組件之間的通信。
Vuex有5個重要的屬性,分別是 State、Getter、Mutation、Action、Module,由 view 層發起一個 Action 給 Mutation,在 Mutation 中修改狀態,返回新的狀態,通過 Getter暴露給 view層的組件或者頁面,頁面監測到狀態改變於是更新頁面。如果你的項目很簡單,最好不要使用 Vuex,對於大型項目,Vuex 能夠更好的幫助我們管理組件外部的狀態,一般可以運用在購物車、登錄狀態、播放等場景中。

3.3. 多個組件之間如何拆分各自的state,每塊小的組件有自己的狀態,它們之間還有一些公共的狀態需要維護,如何思考這塊

  1. 公共的數據部分可以提升至和他們最近的父組件,由父組件派發
  2. 公共數據可以放到vuex中統一管理,各組件分別獲取

4. Router

4.1. vue-router路由的兩種模式

vue-router中默認使用的是hash模式

  1. hash模式, 帶#。如:http://localhost:8080/#/pageA。改變hash,瀏覽器本身不會有任何請求服務器動作的,但是頁面狀態和url已經關聯起來了。
  2. history模式,不帶#, 如:http://localhost:8080/ 正常的而路徑,並沒有#。基於HTML5的 pushState、replaceState實現

4.2. vue-router如何定義嵌套路由

通過children 數組:

const router = new VueRouter({
  routes: [
    {
      path: "/parentPage",
      component: testPage,
      children: [
        {
          path: "/childrenA",
          component: childrenComponentA,
        },
        {
          path: "/childrenB",
          component: childrenComponentB,
        },
      ],
    },
    {
      // 其他和parentPage平級的路由
    },
  ],
});

4.3. vue-router有哪幾種導航鈎子?

  1. 全局導航鈎子:router.beforeEach(to,from,next)
  2. 組件內的鈎子beforeRouteEnter (to, from, next) beforeRouteUpdate (to, from, next) beforeRouteLeave (to, from, next)
  3. 單獨路由獨享組件 beforeEnter: (to, from, next)

4.4. $route和$router的區別

  1. $route是“路由信息對象”,包括path,params,hash,query,fullPath,matched,name等路由信息參數。
  2. $router是“路由實例”對象包括了路由的跳轉方法,鈎子函數等

4.5. 路由之間跳轉的方式

  1. 聲明式(標簽跳轉)
  2. 編程式( js跳轉)

4.6. active-class是哪個組件的屬性

vue-router 模塊 的router-link組件


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM