国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

vue面試題集錦

這篇具有很好參考價(jià)值的文章主要介紹了vue面試題集錦。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

1. 談一談對(duì) MVVM 的理解?

MVVM 是 Model-View-ViewModel 的縮寫。MVVM 是一種設(shè)計(jì)思想。
Model 層代表數(shù)據(jù)模型,也可以在 Model 中定義數(shù)據(jù)修改和操作的業(yè)務(wù)邏輯;
View 代表 UI 組件,它負(fù)責(zé)將數(shù)據(jù)模型轉(zhuǎn)化成 UI 展現(xiàn)出來,View 是一個(gè)同步 View 和 Model 的對(duì)象
在 MVVM 架構(gòu)下,View 和 Model 之間并沒有直接的聯(lián)系,而是通過 ViewModel 進(jìn)行交互, Model 和 ViewModel 之間的交互是雙向的, 因此 View 數(shù)據(jù)的變化會(huì)同步到 Model 中,而 Model 數(shù)據(jù)的變化也會(huì)立即反應(yīng)到 View 上。
對(duì) ViewModel 通過雙向數(shù)據(jù)綁定把 View 層和 Model 層連接了起來,而 View 和 Model 之間的 同步工作完全是自動(dòng)的,無需人為干涉,因此開發(fā)者只需關(guān)注業(yè)務(wù)邏輯,不需要手動(dòng)操作 DOM,不需要關(guān)注數(shù)據(jù)狀態(tài)的同步問題,復(fù)雜的數(shù)據(jù)狀態(tài)維護(hù)完全由 MVVM 來統(tǒng)一管理。


2. 說一下 Vue 的優(yōu)點(diǎn)
?

Vue 是一個(gè)構(gòu)建數(shù)據(jù)驅(qū)動(dòng)的 Web 界面的漸進(jìn)式框架。

Vue 的目標(biāo)是通過盡可能簡(jiǎn)單的 API 實(shí)現(xiàn)響應(yīng)的數(shù)據(jù)綁定和組合的視圖組件。核心是一個(gè)響應(yīng)的數(shù)據(jù)綁定系統(tǒng)。

關(guān)于 Vue 的優(yōu)點(diǎn),主要有響應(yīng)式編程、組件化開發(fā)、虛擬 DOM

響應(yīng)式編程

這里的響應(yīng)式不是 @media 媒體查詢中的響應(yīng)式布局,而是指 Vue 會(huì)自動(dòng)對(duì)頁面中某些數(shù)據(jù)的變化做出響應(yīng)。這也就是 Vue 最大的優(yōu)點(diǎn),通過 MVVM 思想實(shí)現(xiàn)數(shù)據(jù)的雙向綁定,讓開發(fā)者不用再操作 DOM 對(duì)象,有更多的時(shí)間去思考業(yè)務(wù)邏輯。

組件化開發(fā)

Vue 通過組件,把一個(gè)單頁應(yīng)用中的各種模塊拆分到一個(gè)一個(gè)單獨(dú)的組件(component)中,我們只要先在父級(jí)應(yīng)用中寫好各種組件標(biāo)簽(占坑),并且在組件標(biāo)簽中寫好要傳入組件的參數(shù)(就像給函數(shù)傳入?yún)?shù)一樣,這個(gè)參數(shù)叫做組件的屬性),然后再分別寫好各種組件的實(shí)現(xiàn)(填坑),然后整個(gè)應(yīng)用就算做完了。

組件化開發(fā)的優(yōu)點(diǎn):提高開發(fā)效率、方便重復(fù)使用、簡(jiǎn)化調(diào)試步驟、提升整個(gè)項(xiàng)目的可維護(hù)性、便于協(xié)同開發(fā)。

虛擬 DOM

在傳統(tǒng)開發(fā)中,用 JQuery 或者原生的 JavaScript DOM 操作函數(shù)對(duì) DOM 進(jìn)行頻繁操作的時(shí)候,瀏覽器要不停的渲染新的 DOM 樹,導(dǎo)致在性能上面的開銷特別的高。

而 Virtual DOM 則是虛擬 DOM 的英文,簡(jiǎn)單來說,他就是一種可以預(yù)先通過 JavaScript 進(jìn)行各種計(jì)算,把最終的 DOM 操作計(jì)算出來并優(yōu)化,由于這個(gè) DOM 操作屬于預(yù)處理操作,并沒有真實(shí)的操作 DOM,所以叫做虛擬 DOM。最后在計(jì)算完畢才真正將 DOM 操作提交,將 DOM 操作變化反映到 DOM 樹上。


3. 解釋一下對(duì) Vue 生命周期的理解

什么是 vue 生命周期
vue 生命周期的作用是什么
vue 生命周期有幾個(gè)階段
第一次頁面加載會(huì)觸發(fā)哪幾個(gè)鉤子
DOM 渲染在哪個(gè)周期就已經(jīng)完成
多組件(父子組件)中生命周期的調(diào)用順序說一下
?

什么是 vue 生命周期

對(duì)于 vue 來講,生命周期就是一個(gè) vue 實(shí)例從創(chuàng)建到銷毀的過程。

vue 生命周期的作用是什么

在生命周期的過程中會(huì)運(yùn)行著一些叫做生命周期的函數(shù),給予了開發(fā)者在不同的生命周期階段添加業(yè)務(wù)代碼的能力。

其實(shí)和回調(diào)是一個(gè)概念,當(dāng)系統(tǒng)執(zhí)行到某處時(shí),檢查是否有 hook(鉤子),有的話就會(huì)執(zhí)行回調(diào)。

通俗的說,hook 就是在程序運(yùn)行中,在某個(gè)特定的位置,框架的開發(fā)者設(shè)計(jì)好了一個(gè)鉤子來告訴我們當(dāng)前程序已經(jīng)運(yùn)行到特定的位置了,會(huì)觸發(fā)一個(gè)回調(diào)函數(shù),并提供給我們,讓我們可以在生命周期的特定階段進(jìn)行相關(guān)業(yè)務(wù)代碼的編寫。

vue 生命周期有幾個(gè)階段

它可以總共分為 8 個(gè)階段:創(chuàng)建前/后, 載入前/后,更新前/后,銷毀前/銷毀后。

beforeCreate:是 new Vue( ) 之后觸發(fā)的第一個(gè)鉤子,在當(dāng)前階段 data、methods、computed 以及 watch 上的數(shù)據(jù)和方法都不能被訪問。

created:在實(shí)例創(chuàng)建完成后發(fā)生,當(dāng)前階段已經(jīng)完成了數(shù)據(jù)觀測(cè),也就是可以使用數(shù)據(jù),更改數(shù)據(jù),在這里更改數(shù)據(jù)不會(huì)觸發(fā) updated 函數(shù)。可以做一些初始數(shù)據(jù)的獲取,在當(dāng)前階段無法與 DOM 進(jìn)行交互,如果非要想,可以通過 vm.$nextTick 來訪問 DOM 。

beforeMount:發(fā)生在掛載之前,在這之前 template 模板已導(dǎo)入渲染函數(shù)編譯。而當(dāng)前階段虛擬 DOM 已經(jīng)創(chuàng)建完成,即將開始渲染。在此時(shí)也可以對(duì)數(shù)據(jù)進(jìn)行更改,不會(huì)觸發(fā) updated。

mounted:在掛載完成后發(fā)生,在當(dāng)前階段,真實(shí)的 DOM 掛載完畢,數(shù)據(jù)完成雙向綁定,可以訪問到 DOM 節(jié)點(diǎn),使用 $refs 屬性對(duì) DOM 進(jìn)行操作。

beforeUpdate:發(fā)生在更新之前,也就是響應(yīng)式數(shù)據(jù)發(fā)生更新,虛擬 DOM 重新渲染之前被觸發(fā),你可以在當(dāng)前階段進(jìn)行更改數(shù)據(jù),不會(huì)造成重渲染。

updated:發(fā)生在更新完成之后,當(dāng)前階段組件 DOM 已完成更新。要注意的是避免在此期間更改數(shù)據(jù),因?yàn)檫@可能會(huì)導(dǎo)致無限循環(huán)的更新。

beforeDestroy:發(fā)生在實(shí)例銷毀之前,在當(dāng)前階段實(shí)例完全可以被使用,我們可以在這時(shí)進(jìn)行善后收尾工作,比如清除計(jì)時(shí)器。

destroyed:發(fā)生在實(shí)例銷毀之后,這個(gè)時(shí)候只剩下了 DOM 空殼。組件已被拆解,數(shù)據(jù)綁定被卸除,監(jiān)聽被移出,子實(shí)例也統(tǒng)統(tǒng)被銷毀。

第一次頁面加載會(huì)觸發(fā)哪幾個(gè)鉤子

會(huì)觸發(fā) 4 個(gè)鉤子,分別是:beforeCreate、created、beforeMount、mounted

DOM 渲染在哪個(gè)周期就已經(jīng)完成

DOM 渲染是在 mounted 階段完成,此階段真實(shí)的 DOM 掛載完畢,數(shù)據(jù)完成雙向綁定,可以訪問到 DOM 節(jié)點(diǎn)。

多組件(父子組件)中生命周期的調(diào)用順序說一下

組件的調(diào)用順序都是先父后子,渲染完成的順序是先子后父。組件的銷毀操作是先父后子,銷毀完成的順序是先子后父。

加載渲染過程:父beforeCreate->父created->父beforeMount->子beforeCreate->子created->子beforeMount- >子mounted->父mounted

子組件更新過程:父beforeUpdate->子beforeUpdate->子updated->父updated

父組件更新過程:父 beforeUpdate -> 父 updated

銷毀過程:父beforeDestroy->子beforeDestroy->子destroyed->父destroyed

4. Vue 實(shí)現(xiàn)雙向數(shù)據(jù)綁定原理是什么?

Vue2.x 采用數(shù)據(jù)劫持結(jié)合發(fā)布訂閱模式(PubSub 模式)的方式,通過 Object.defineProperty 來劫持各個(gè)屬性的 setter、getter,在數(shù)據(jù)變動(dòng)時(shí)發(fā)布消息給訂閱者,觸發(fā)相應(yīng)的監(jiān)聽回調(diào)。

當(dāng)把一個(gè)普通 Javascript 對(duì)象傳給 Vue 實(shí)例來作為它的 data 選項(xiàng)時(shí),Vue 將遍歷它的屬性,用 Object.defineProperty 將它們轉(zhuǎn)為 getter/setter。用戶看不到 getter/setter,但是在內(nèi)部它們讓 Vue 追蹤依賴,在屬性被訪問和修改時(shí)通知變化。

Vue 的數(shù)據(jù)雙向綁定整合了 Observer,Compile 和 Watcher 三者,通過 Observer 來監(jiān)聽自己的 model 的數(shù)據(jù)變化,通過 Compile 來解析編譯模板指令,最終利用 Watcher 搭起 Observer 和 Compile 之間的通信橋梁,達(dá)到數(shù)據(jù)變化->視圖更新,視圖交互變化(例如 input 操作)->數(shù)據(jù) model 變更的雙向綁定效果。

Vue3.x 放棄了 Object.defineProperty ,使用 ES6 原生的 Proxy,來解決以前使用 Object.defineProperty 所存在的一些問題。

5. 說一下對(duì) Vue2.x 響應(yīng)式原理的理解

Vue 在初始化數(shù)據(jù)時(shí),會(huì)使用 Object.defineProperty 重新定義 data 中的所有屬性,當(dāng)頁面使用對(duì)應(yīng)屬性時(shí),首先會(huì)進(jìn)行依賴收集(收集當(dāng)前組件的 watcher),如果屬性發(fā)生變化會(huì)通知相關(guān)依賴進(jìn)行更新操作(發(fā)布訂閱)。

6. 說一下在 Vue2.x 中如何檢測(cè)數(shù)組的變化?

Vue2.x 中實(shí)現(xiàn)檢測(cè)數(shù)組變化的方法,是將數(shù)組的常用方法進(jìn)行了重寫。

Vue 將 data 中的數(shù)組進(jìn)行了原型鏈重寫,指向了自己定義的數(shù)組原型方法。這樣當(dāng)調(diào)用數(shù)組 api 時(shí),可以通知依賴更新。如果數(shù)組中包含著引用類型,會(huì)對(duì)數(shù)組中的引用類型再次遞歸遍歷進(jìn)行監(jiān)控。這樣就實(shí)現(xiàn)了監(jiān)測(cè)數(shù)組變化。

流程:

初始化傳入 data 數(shù)據(jù)執(zhí)行 initData
將數(shù)據(jù)進(jìn)行觀測(cè) new Observer
將數(shù)組原型方法指向重寫的原型
深度觀察數(shù)組中的引用類型
有兩種情況無法檢測(cè)到數(shù)組的變化。

當(dāng)利用索引直接設(shè)置一個(gè)數(shù)組項(xiàng)時(shí),例如 vm.items[indexOfItem] = newValue
當(dāng)修改數(shù)組的長(zhǎng)度時(shí),例如 vm.items.length = newLength
不過這兩種場(chǎng)景都有對(duì)應(yīng)的解決方案。

利用索引設(shè)置數(shù)組項(xiàng)的替代方案

//使用該方法進(jìn)行更新視圖
// vm.$set,Vue.set的一個(gè)別名
vm.$set(vm.items, indexOfItem, newValue)

修改數(shù)組的長(zhǎng)度的替代方案

//使用該方法進(jìn)行更新視圖
// Array.prototype.splice
vm.items.splice(indexOfItem, 1, newValue)


7. Vue3.x 響應(yīng)式數(shù)據(jù)

Vue3.x 響應(yīng)式數(shù)據(jù)原理是什么?
Proxy 只會(huì)代理對(duì)象的第一層,那么 Vue3 又是怎樣處理這個(gè)問題的呢?
監(jiān)測(cè)數(shù)組的時(shí)候可能觸發(fā)多次 get/set,那么如何防止觸發(fā)多次呢?
?

Vue3.x 響應(yīng)式數(shù)據(jù)原理是什么?

在 Vue 2 中,響應(yīng)式原理就是使用的 Object.defineProperty 來實(shí)現(xiàn)的。但是在 Vue 3.0 中采用了 Proxy,拋棄了 Object.defineProperty 方法。

究其原因,主要是以下幾點(diǎn):

Object.defineProperty 無法監(jiān)控到數(shù)組下標(biāo)的變化,導(dǎo)致通過數(shù)組下標(biāo)添加元素,不能實(shí)時(shí)響應(yīng)
Object.defineProperty 只能劫持對(duì)象的屬性,從而需要對(duì)每個(gè)對(duì)象,每個(gè)屬性進(jìn)行遍歷,如果,屬性值是對(duì)象,還需要深度遍歷。Proxy 可以劫持整個(gè)對(duì)象,并返回一個(gè)新的對(duì)象。
Proxy 不僅可以代理對(duì)象,還可以代理數(shù)組。還可以代理動(dòng)態(tài)增加的屬性。
Proxy 有多達(dá) 13 種攔截方法
Proxy作為新標(biāo)準(zhǔn)將受到瀏覽器廠商重點(diǎn)持續(xù)的性能優(yōu)化
Proxy 只會(huì)代理對(duì)象的第一層,那么 Vue3 又是怎樣處理這個(gè)問題的呢?

判斷當(dāng)前 Reflect.get 的返回值是否為 Object,如果是則再通過 reactive 方法做代理, 這樣就實(shí)現(xiàn)了深度觀測(cè)。

監(jiān)測(cè)數(shù)組的時(shí)候可能觸發(fā)多次 get/set,那么如何防止觸發(fā)多次呢?

我們可以判斷 key 是否為當(dāng)前被代理對(duì)象 target 自身屬性,也可以判斷舊值與新值是否相等,只有滿足以上兩個(gè)條件之一時(shí),才有可能執(zhí)行 trigger。

8. v-model 雙向綁定的原理是什么?

v-model 本質(zhì)就是 :value + input 方法的語法糖??梢酝ㄟ^ model 屬性的 prop 和 event 屬性來進(jìn)行自定義。原生的 v-model,會(huì)根據(jù)標(biāo)簽的不同生成不同的事件和屬性。

例如:

text 和 textarea 元素使用 value 屬性和 input 事件
checkbox 和 radio 使用 checked 屬性和 change 事件
select 字段將 value 作為 prop 并將 change 作為事件
以輸入框?yàn)槔?dāng)用戶在輸入框輸入內(nèi)容時(shí),會(huì)觸發(fā) input 事件,從而更新 value。而 value 的改變同樣會(huì)更新視圖,這就是 vue 中的雙向綁定。雙向綁定的原理,其實(shí)現(xiàn)思路如下:

首先要對(duì)數(shù)據(jù)進(jìn)行劫持監(jiān)聽,所以我們需要設(shè)置一個(gè)監(jiān)聽器 Observer,用來監(jiān)聽所有屬性。如果屬性發(fā)上變化了,就需要告訴訂閱者 Watcher 看是否需要更新。

因?yàn)橛嗛喺呤怯泻芏鄠€(gè),所以我們需要有一個(gè)消息訂閱器 Dep 來專門收集這些訂閱者,然后在監(jiān)聽器 Observer 和訂閱者 Watcher 之間進(jìn)行統(tǒng)一管理的。

接著,我們還需要有一個(gè)指令解析器 Compile,對(duì)每個(gè)節(jié)點(diǎn)元素進(jìn)行掃描和解析,將相關(guān)指令對(duì)應(yīng)初始化成一個(gè)訂閱者 Watcher,并替換模板數(shù)據(jù)或者綁定相應(yīng)的函數(shù),此時(shí)當(dāng)訂閱者 Watcher 接收到相應(yīng)屬性的變化,就會(huì)執(zhí)行對(duì)應(yīng)的更新函數(shù),從而更新視圖。

因此接下去我們執(zhí)行以下 3 個(gè)步驟,實(shí)現(xiàn)數(shù)據(jù)的雙向綁定:

實(shí)現(xiàn)一個(gè)監(jiān)聽器 Observer,用來劫持并監(jiān)聽所有屬性,如果有變動(dòng)的,就通知訂閱者。

實(shí)現(xiàn)一個(gè)訂閱者 Watcher,可以收到屬性的變化通知并執(zhí)行相應(yīng)的函數(shù),從而更新視圖。

實(shí)現(xiàn)一個(gè)解析器 Compile,可以掃描和解析每個(gè)節(jié)點(diǎn)的相關(guān)指令,并根據(jù)初始化模板數(shù)據(jù)以及初始化相應(yīng)的訂閱器。


9. vue2.x 和 vuex3.x 渲染器的 diff 算法分別說一下?
?

簡(jiǎn)單來說,diff 算法有以下過程

同級(jí)比較,再比較子節(jié)點(diǎn)
先判斷一方有子節(jié)點(diǎn)一方?jīng)]有子節(jié)點(diǎn)的情況(如果新的 children 沒有子節(jié)點(diǎn),將舊的子節(jié)點(diǎn)移除)
比較都有子節(jié)點(diǎn)的情況(核心 diff)
遞歸比較子節(jié)點(diǎn)
正常 Diff 兩個(gè)樹的時(shí)間復(fù)雜度是 O(n^3),但實(shí)際情況下我們很少會(huì)進(jìn)行跨層級(jí)的移動(dòng) DOM,所以 Vue 將 Diff 進(jìn)行了優(yōu)化,從O(n^3) -> O(n),只有當(dāng)新舊 children 都為多個(gè)子節(jié)點(diǎn)時(shí)才需要用核心的 Diff 算法進(jìn)行同層級(jí)比較。

Vue2 的核心 Diff 算法采用了雙端比較的算法,同時(shí)從新舊 children 的兩端開始進(jìn)行比較,借助 key 值找到可復(fù)用的節(jié)點(diǎn),再進(jìn)行相關(guān)操作。相比 React 的 Diff 算法,同樣情況下可以減少移動(dòng)節(jié)點(diǎn)次數(shù),減少不必要的性能損耗,更加的優(yōu)雅。

Vue3.x 借鑒了 ivi 算法和 inferno 算法

在創(chuàng)建 VNode 時(shí)就確定其類型,以及在 mount/patch 的過程中采用位運(yùn)算來判斷一個(gè) VNode 的類型,在這個(gè)基礎(chǔ)之上再配合核心的 Diff 算法,使得性能上較 Vue2.x 有了提升。該算法中還運(yùn)用了動(dòng)態(tài)規(guī)劃的思想求解最長(zhǎng)遞歸子序列。


10. vue 組件的參數(shù)傳遞

解釋一下父組件與子組件傳值實(shí)現(xiàn)過程
非父子組件的數(shù)據(jù)傳遞,兄弟組件傳值是如何實(shí)現(xiàn)的
?

解釋一下父組件與子組件傳值實(shí)現(xiàn)過程

父組件傳給子組件:子組件通過 props 方法接受數(shù)據(jù)

子組件傳給父組件:使用自定義事件,自組件通過 $emit 方法觸發(fā)父組件的方法來傳遞參數(shù)

非父子組件的數(shù)據(jù)傳遞,兄弟組件傳值是如何實(shí)現(xiàn)的

eventBus,就是創(chuàng)建一個(gè)事件中心,相當(dāng)于中轉(zhuǎn)站,可以用它來傳遞事件和接收事件。項(xiàng)目比較小時(shí),用這個(gè)比較合適。

此外,總結(jié) vue 中的組件通信方式,常見使用場(chǎng)景可以分為三類:

父子通信:
父向子傳遞數(shù)據(jù)是通過 props ,子向父是通過 $emit / $on
$emit / $bus
vuex
通過父鏈 / 子鏈也可以通信( $parent / $children )
ref 也可以訪問組件實(shí)例
v-model
.sync 修飾符
兄弟通信:
$emit / $bus
vuex
跨級(jí)通信:
$emit / $bus
vuex
provide / inject API
a t t r s / attrs/attrs/listeners


11. Vue 的路由實(shí)現(xiàn)

解釋 hash 模式和 history 模式的實(shí)現(xiàn)原理
說一下 r o u t e r ? 與 ? router* 與 *router?與?route 的區(qū)別
vueRouter 有哪幾種導(dǎo)航守衛(wèi)?
解釋一下 vueRouter 的完整的導(dǎo)航解析流程是什么
?

解釋 hash 模式和 history 模式的實(shí)現(xiàn)原理

# 后面 hash 值的變化,不會(huì)導(dǎo)致瀏覽器向服務(wù)器發(fā)出請(qǐng)求,瀏覽器不發(fā)出請(qǐng)求,就不會(huì)刷新頁面;通過監(jiān)聽 hashchange 事件可以知道 hash 發(fā)生了哪些變化,然后根據(jù) hash 變化來實(shí)現(xiàn)更新頁面部分內(nèi)容的操作。

history 模式的實(shí)現(xiàn),主要是 HTML5 標(biāo)準(zhǔn)發(fā)布的兩個(gè) API,pushState 和 replaceState,這兩個(gè) API 可以在改變 URL,但是不會(huì)發(fā)送請(qǐng)求。這樣就可以監(jiān)聽 url 變化來實(shí)現(xiàn)更新頁面部分內(nèi)容的操作。

兩種模式的區(qū)別:

首先是在 URL 的展示上,hash 模式有“#”,history 模式?jīng)]有

刷新頁面時(shí),hash 模式可以正常加載到 hash 值對(duì)應(yīng)的頁面,而 history 沒有處理的話,會(huì)返回 404,一般需要后端將所有頁面都配置重定向到首頁路由

在兼容性上,hash 可以支持低版本瀏覽器和 IE

說一下 r o u t e r ? 與 ? router* 與 *router?與?route 的區(qū)別

$route 對(duì)象表示當(dāng)前的路由信息,包含了當(dāng)前 URL 解析得到的信息。包含當(dāng)前的路徑,參數(shù),query 對(duì)象等。

$route.path:字符串,對(duì)應(yīng)當(dāng)前路由的路徑,總是解析為絕對(duì)路徑,如 “/foo/bar”。
$route.params: 一個(gè) key/value 對(duì)象,包含了 動(dòng)態(tài)片段 和 全匹配片段,如果沒有路由參數(shù),就是一個(gè)空對(duì)象。
r o u t e . q u e r y ? :一個(gè) k e y / v a l u e 對(duì)象,表示 U R L 查詢參數(shù)。例如對(duì)于路徑 ? / f o o ? u s e r = 1 ? ,則有 ? route.query*:一個(gè) key/value 對(duì)象,表示 URL 查詢參數(shù)。例如對(duì)于路徑 */foo?user=1*,則有 *route.query?:一個(gè)key/value對(duì)象,表示URL查詢參數(shù)。例如對(duì)于路徑?/foo?user=1?,則有?route.query.user == 1,如果沒有查詢參數(shù),則是個(gè)空對(duì)象。
$route.hash:當(dāng)前路由的 hash 值 (不帶 #) ,如果沒有 hash 值,則為空字符串。
$route.fullPath:完成解析后的 URL,包含查詢參數(shù)和 hash 的完整路徑。
$route.matched:數(shù)組,包含當(dāng)前匹配的路徑中所包含的所有片段所對(duì)應(yīng)的配置參數(shù)對(duì)象。
$route.name:當(dāng)前路徑名字
$route.meta:路由元信息
$route 對(duì)象出現(xiàn)在多個(gè)地方:

組件內(nèi)的 this.$route 和 route watcher 回調(diào)(監(jiān)測(cè)變化處理)
router.match(location) 的返回值
scrollBehavior 方法的參數(shù)
導(dǎo)航鉤子的參數(shù),例如 router.beforeEach 導(dǎo)航守衛(wèi)的鉤子函數(shù)中,to 和 from 都是這個(gè)路由信息對(duì)象。
$router 對(duì)象是全局路由的實(shí)例,是 router 構(gòu)造方法的實(shí)例。

$router 對(duì)象常用的方法有:

push:向 history 棧添加一個(gè)新的記錄
go:頁面路由跳轉(zhuǎn)前進(jìn)或者后退
replace:替換當(dāng)前的頁面,不會(huì)向 history 棧添加一個(gè)新的記錄
vueRouter 有哪幾種導(dǎo)航守衛(wèi)?

全局前置/鉤子:beforeEach、beforeR-esolve、afterEach

路由獨(dú)享的守衛(wèi):beforeEnter

組件內(nèi)的守衛(wèi):beforeRouteEnter、beforeRouteUpdate、beforeRouteLeave

解釋一下 vueRouter 的完整的導(dǎo)航解析流程是什么

一次完整的導(dǎo)航解析流程如下:

導(dǎo)航被觸發(fā)。
在失活的組件里調(diào)用離開守衛(wèi)。
調(diào)用全局的 beforeEach 守衛(wèi)。
在重用的組件里調(diào)用 beforeRouteUpdate 守衛(wèi)(2.2+)。
在路由配置里調(diào)用 beforeEnter。
解析異步路由組件。
在被激活的組件里調(diào)用 beforeRouteEnter。
調(diào)用全局的 beforeResolve 守衛(wèi)(2.5+)。
導(dǎo)航被確認(rèn)。
調(diào)用全局的 afterEach 鉤子。
觸發(fā) DOM 更新。
用創(chuàng)建好的實(shí)例調(diào)用 beforeRouteEnter 守衛(wèi)中傳給 next 的回調(diào)函數(shù)。


12. vuex 是什么?怎么使用它?什么場(chǎng)景下我們會(huì)使用到 vuex
?

vuex 是什么

vuex 是一個(gè)專為 Vue 應(yīng)用程序開發(fā)的狀態(tài)管理器,采用集中式存儲(chǔ)管理應(yīng)用的所有組件的狀態(tài)。每一個(gè) vuex 應(yīng)用的核心就是 store(倉庫)?!皊tore” 基本上就是一個(gè)容器,它包含著應(yīng)用中大部分的狀態(tài) (state)。

為什么需要 vuex

由于組件只維護(hù)自身的狀態(tài)(data),組件創(chuàng)建時(shí)或者路由切換時(shí),組件會(huì)被初始化,從而導(dǎo)致 data 也隨之銷毀。

使用方法

在 main.js 引入 store,注入。只用來讀取的狀態(tài)集中放在 store 中, 改變狀態(tài)的方式是提交 mutations,這是個(gè)同步的事物,異步邏輯應(yīng)該封裝在 action 中。

什么場(chǎng)景下會(huì)使用到 vuex

如果是 vue 的小型應(yīng)用,那么沒有必要使用 vuex,這個(gè)時(shí)候使用 vuex 反而會(huì)帶來負(fù)擔(dān)。組件之間的狀態(tài)傳遞使用 props、自定義事件來傳遞即可。

但是如果涉及到 vue 的大型應(yīng)用,那么就需要類似于 vuex 這樣的集中管理狀態(tài)的狀態(tài)機(jī)來管理所有組件的狀態(tài)。例如登錄狀態(tài)、加入購(gòu)物車、音樂播放等,總之只要是開發(fā) vue 的大型應(yīng)用,都推薦使用 vuex 來管理所有組件狀態(tài)。

13. 說一下 v-for 與 v-show 的區(qū)別
?

共同點(diǎn):都是動(dòng)態(tài)顯示 DOM 元素

區(qū)別點(diǎn):

手段

v-if 是動(dòng)態(tài)的向 DOM 樹內(nèi)添加或者刪除 DOM 元素

v-show 是通過設(shè)置 DOM 元素的 display 樣式屬性控制顯隱

編譯過程

v-if 切換有一個(gè)局部編譯/卸載的過程,切換過程中合適地銷毀和重建內(nèi)部的事件監(jiān)聽和子組件

v-show 只是簡(jiǎn)單的基于 css 切換

編譯條件

v-if 是惰性的,如果初始條件為假,則什么也不做。只有在條件第一次變?yōu)檎鏁r(shí)才開始局部編譯

v-show 是在任何條件下(首次條件是否為真)都被編譯,然后被緩存,而且 DOM 元素保留

性能消耗

v-if 有更高的切換消耗

v-show 有更高的初始渲染消耗

使用場(chǎng)景

v-if 適合運(yùn)營(yíng)條件不大可能改變

v-show 適合頻繁切換

14. 如何讓 CSS 值在當(dāng)前的組件中起作用
?

在 vue 文件中的 style 標(biāo)簽上,有一個(gè)特殊的屬性:scoped。當(dāng)一個(gè) style 標(biāo)簽擁有 scoped 屬性時(shí),它的 CSS 樣式就只能作用于當(dāng)前的組件,也就是說,該樣式只能適用于當(dāng)前組件元素。通過該屬性,可以使得組件之間的樣式不互相污染。如果一個(gè)項(xiàng)目中的所有 style 標(biāo)簽全部加上了 scoped,相當(dāng)于實(shí)現(xiàn)了樣式的模塊化。

scoped 的實(shí)現(xiàn)原理

vue 中的 scoped 屬性的效果主要通過 PostCSS 轉(zhuǎn)譯實(shí)現(xiàn)的。PostCSS 給一個(gè)組件中的所有 DOM 添加了一個(gè)獨(dú)一無二的動(dòng)態(tài)屬性,然后,給 CSS 選擇器額外添加一個(gè)對(duì)應(yīng)的屬性選擇器來選擇該組件中 DOM,這種做法使得樣式只作用于含有該屬性的 DOM,即組件內(nèi)部 DOM。

例如:

轉(zhuǎn)譯前

<template>
? <div class="example">hi</div>
</template>

<style scoped>
.example {
? color: red;
}
</style>
轉(zhuǎn)譯后:

<template>
? <div class="example" data-v-5558831a>hi</div>
</template>

<style>
.example[data-v-5558831a] {
? color: red;
}
</style>


15. keep-alive 相關(guān)

keep-alive的實(shí)現(xiàn)原理是什么
與keep-alive相關(guān)的生命周期函數(shù)是什么,什么場(chǎng)景下會(huì)進(jìn)行使用
keep-alive的常用屬性有哪些
?

keep-alive 組件是 vue 的內(nèi)置組件,用于緩存內(nèi)部組件實(shí)例。這樣做的目的在于,keep-alive 內(nèi)部的組件切回時(shí),不用重新創(chuàng)建組件實(shí)例,而直接使用緩存中的實(shí)例,一方面能夠避免創(chuàng)建組件帶來的開銷,另一方面可以保留組件的狀態(tài)。

keep-alive 具有 include 和 exclude 屬性,通過它們可以控制哪些組件進(jìn)入緩存。另外它還提供了 max 屬性,通過它可以設(shè)置最大緩存數(shù),當(dāng)緩存的實(shí)例超過該數(shù)時(shí),vue 會(huì)移除最久沒有使用的組件緩存。

受keep-alive的影響,其內(nèi)部所有嵌套的組件都具有兩個(gè)生命周期鉤子函數(shù),分別是 activated 和 deactivated,它們分別在組件激活和失活時(shí)觸發(fā)。第一次 activated 觸發(fā)是在 mounted 之后

在具體的實(shí)現(xiàn)上,keep-alive 在內(nèi)部維護(hù)了一個(gè) key 數(shù)組和一個(gè)緩存對(duì)象

// keep-alive 內(nèi)部的聲明周期函數(shù)
created () {
? ? this.cache = Object.create(null)
? ? this.keys = []
}

key 數(shù)組記錄目前緩存的組件 key 值,如果組件沒有指定 key 值,則會(huì)為其自動(dòng)生成一個(gè)唯一的 key 值

cache 對(duì)象以 key 值為鍵,vnode 為值,用于緩存組件對(duì)應(yīng)的虛擬 DOM

在 keep-alive 的渲染函數(shù)中,其基本邏輯是判斷當(dāng)前渲染的 vnode 是否有對(duì)應(yīng)的緩存,如果有,從緩存中讀取到對(duì)應(yīng)的組件實(shí)例;如果沒有則將其緩存。

當(dāng)緩存數(shù)量超過 max 數(shù)值時(shí),keep-alive 會(huì)移除掉 key 數(shù)組的第一個(gè)元素。

16. Vue 中如何進(jìn)行組件的使用?Vue 如何實(shí)現(xiàn)全局組件的注冊(cè)?
?

要使用組件,首先需要使用 import 來引入組件,然后在 components 屬性中注冊(cè)組件,之后就可以在模板中使用組件了。

可以使用 Vue.component 方法來實(shí)現(xiàn)全局組件的注冊(cè)。


17. vue-cli 工程相關(guān)

構(gòu)建 vue-cli 工程都用到了哪些技術(shù)?他們的作用分別是什么?
vue-cli 工程常用的 npm 命令有哪些?

構(gòu)建 vue-cli 工程都用到了哪些技術(shù)?他們的作用分別是什么?

vue.js:vue-cli 工程的核心,主要特點(diǎn)是雙向數(shù)據(jù)綁定和組件系統(tǒng)。
vue-router:vue 官方推薦使用的路由框架。
vuex:專為 Vue.js 應(yīng)用項(xiàng)目開發(fā)的狀態(tài)管理器,主要用于維護(hù) vue 組件間共用的一些 變量 和 方法。
axios(或者 fetch、ajax):用于發(fā)起 GET 、或 POST 等 http請(qǐng)求,基于 Promise 設(shè)計(jì)。
vux等:一個(gè)專為vue設(shè)計(jì)的移動(dòng)端UI組件庫。
webpack:模塊加載和vue-cli工程打包器。
eslint:代碼規(guī)范工具
vue-cli 工程常用的 npm 命令有哪些?

下載 node_modules 資源包的命令:npm install

啟動(dòng) vue-cli 開發(fā)環(huán)境的 npm命令:npm run dev

vue-cli 生成 生產(chǎn)環(huán)境部署資源 的 npm命令:npm run build

用于查看 vue-cli 生產(chǎn)環(huán)境部署資源文件大小的 npm命令:npm run build --report

18. nextTick 的作用是什么?他的實(shí)現(xiàn)原理是什么?
?

作用:vue 更新 DOM 是異步更新的,數(shù)據(jù)變化,DOM 的更新不會(huì)馬上完成,nextTick 的回調(diào)是在下次 DOM 更新循環(huán)結(jié)束之后執(zhí)行的延遲回調(diào)。

實(shí)現(xiàn)原理:nextTick 主要使用了宏任務(wù)和微任務(wù)。根據(jù)執(zhí)行環(huán)境分別嘗試采用

Promise:可以將函數(shù)延遲到當(dāng)前函數(shù)調(diào)用棧最末端
MutationObserver :是 H5 新加的一個(gè)功能,其功能是監(jiān)聽 DOM 節(jié)點(diǎn)的變動(dòng),在所有 DOM 變動(dòng)完成后,執(zhí)行回調(diào)函數(shù)
setImmediate:用于中斷長(zhǎng)時(shí)間運(yùn)行的操作,并在瀏覽器完成其他操作(如事件和顯示更新)后立即運(yùn)行回調(diào)函數(shù)
如果以上都不行則采用 setTimeout 把函數(shù)延遲到 DOM 更新之后再使用
原因是宏任務(wù)消耗大于微任務(wù),優(yōu)先使用微任務(wù),最后使用消耗最大的宏任務(wù)。

19. 說一下 Vue SSR 的實(shí)現(xiàn)原理
?

app.js 作為客戶端與服務(wù)端的公用入口,導(dǎo)出 Vue 根實(shí)例,供客戶端 entry 與服務(wù)端 entry 使用。客戶端 entry 主要作用掛載到 DOM 上,服務(wù)端 entry 除了創(chuàng)建和返回實(shí)例,還需要進(jìn)行路由匹配與數(shù)據(jù)預(yù)獲取。
webpack 為客服端打包一個(gè) ClientBundle,為服務(wù)端打包一個(gè) ServerBundle。
服務(wù)器接收請(qǐng)求時(shí),會(huì)根據(jù) url,加載相應(yīng)組件,獲取和解析異步數(shù)據(jù),創(chuàng)建一個(gè)讀取 Server Bundle 的 BundleRenderer,然后生成 html 發(fā)送給客戶端。
客戶端混合,客戶端收到從服務(wù)端傳來的 DOM 與自己的生成的 DOM 進(jìn)行對(duì)比,把不相同的 DOM 激活,使其可以能夠響應(yīng)后續(xù)變化,這個(gè)過程稱為客戶端激活(也就是轉(zhuǎn)換為單頁應(yīng)用)。為確保混合成功,客戶 端與服務(wù)器端需要共享同一套數(shù)據(jù)。在服務(wù)端,可以在渲染之前獲取數(shù)據(jù),填充到 store 里,這樣,在客戶端掛載到 DOM 之前,可以直接從 store 里取數(shù)據(jù)。首屏的動(dòng)態(tài)數(shù)據(jù)通過 window._INITIAL_STATE_ 發(fā)送到客戶端
VueSSR 的原理,主要就是通過 vue-server-renderer 把 Vue 的組件輸出成一個(gè)完整 HTML,輸出到客戶端,到達(dá)客戶端后重新展開為一個(gè)單頁應(yīng)用。


20. Vue 組件的 data 為什么必須是函數(shù)
?

組件中的 data 寫成一個(gè)函數(shù),數(shù)據(jù)以函數(shù)返回值形式定義。這樣每復(fù)用一次組件,就會(huì)返回一份新的 data,類似于給每個(gè)組件實(shí)例創(chuàng)建一個(gè)私有的數(shù)據(jù)空間,讓各個(gè)組件實(shí)例維護(hù)各自的數(shù)據(jù)。而單純的寫成對(duì)象形式,就使得所有組件實(shí)例共用了一份 data,就會(huì)造成一個(gè)變了全都會(huì)變的結(jié)果。

21. 說一下 Vue 的 computed 的實(shí)現(xiàn)原理
?

當(dāng)組件實(shí)例觸發(fā)生命周期函數(shù) beforeCreate 后,它會(huì)做一系列事情,其中就包括對(duì) computed 的處理。

它會(huì)遍歷 computed 配置中的所有屬性,為每一個(gè)屬性創(chuàng)建一個(gè) Watcher 對(duì)象,并傳入一個(gè)函數(shù),該函數(shù)的本質(zhì)其實(shí)就是 computed 配置中的 getter,這樣一來,getter 運(yùn)行過程中就會(huì)收集依賴

但是和渲染函數(shù)不同,為計(jì)算屬性創(chuàng)建的 Watcher 不會(huì)立即執(zhí)行,因?yàn)橐紤]到該計(jì)算屬性是否會(huì)被渲染函數(shù)使用,如果沒有使用,就不會(huì)得到執(zhí)行。因此,在創(chuàng)建 Watcher 的時(shí)候,它使用了 lazy 配置,lazy 配置可以讓 Watcher 不會(huì)立即執(zhí)行。

收到 lazy 的影響,Watcher 內(nèi)部會(huì)保存兩個(gè)關(guān)鍵屬性來實(shí)現(xiàn)緩存,一個(gè)是 value,一個(gè)是 dirty

value 屬性用于保存 Watcher 運(yùn)行的結(jié)果,受 lazy 的影響,該值在最開始是 undefined

dirty 屬性用于指示當(dāng)前的 value 是否已經(jīng)過時(shí)了,即是否為臟值,受 lazy 的影響,該值在最開始是 true

Watcher 創(chuàng)建好后,vue 會(huì)使用代理模式,將計(jì)算屬性掛載到組件實(shí)例中

當(dāng)讀取計(jì)算屬性時(shí),vue 檢查其對(duì)應(yīng)的 Watcher 是否是臟值,如果是,則運(yùn)行函數(shù),計(jì)算依賴,并得到對(duì)應(yīng)的值,保存在 Watcher 的 value 中,然后設(shè)置 dirty 為 false,然后返回。

如果 dirty 為 false,則直接返回 watcher 的 value

巧妙的是,在依賴收集時(shí),被依賴的數(shù)據(jù)不僅會(huì)收集到計(jì)算屬性的 Watcher,還會(huì)收集到組件的 Watcher

當(dāng)計(jì)算屬性的依賴變化時(shí),會(huì)先觸發(fā)計(jì)算屬性的 Watcher 執(zhí)行,此時(shí),它只需設(shè)置 dirty 為 true 即可,不做任何處理。

由于依賴同時(shí)會(huì)收集到組件的 Watcher,因此組件會(huì)重新渲染,而重新渲染時(shí)又讀取到了計(jì)算屬性,由于計(jì)算屬性目前已為 dirty,因此會(huì)重新運(yùn)行 getter 進(jìn)行運(yùn)算

而對(duì)于計(jì)算屬性的 setter,則極其簡(jiǎn)單,當(dāng)設(shè)置計(jì)算屬性時(shí),直接運(yùn)行 setter 即可。

22. 說一下 Vue complier 的實(shí)現(xiàn)原理是什么樣的?
?

在使用 vue 的時(shí)候,我們有兩種方式來創(chuàng)建我們的 HTML 頁面,第一種情況,也是大多情況下,我們會(huì)使用模板 template 的方式,因?yàn)檫@更易讀易懂也是官方推薦的方法;第二種情況是使用 render 函數(shù)來生成 HTML,它比 template 更接近最終結(jié)果。

complier 的主要作用是解析模板,生成渲染模板的 render, 而 render 的作用主要是為了生成 VNode

complier 主要分為 3 大塊:

parse:接受 template 原始模板,按著模板的節(jié)點(diǎn)和數(shù)據(jù)生成對(duì)應(yīng)的 ast
optimize:遍歷 ast 的每一個(gè)節(jié)點(diǎn),標(biāo)記靜態(tài)節(jié)點(diǎn),這樣就知道哪部分不會(huì)變化,于是在頁面需要更新時(shí),通過 diff 減少去對(duì)比這部分DOM,提升性能
generate 把前兩步生成完善的 ast,組成 render 字符串,然后將 render 字符串通過 new Function 的方式轉(zhuǎn)換成渲染函數(shù)


23. vue 如何快速定位那個(gè)組件出現(xiàn)性能問題的
?

? timeline ?具。 通過 timeline 來查看每個(gè)函數(shù)的調(diào)?時(shí)常,定位出哪個(gè)函數(shù)的問題,從?能判斷哪個(gè)組件出了問題。

24. Proxy 相比 defineProperty 的優(yōu)勢(shì)在哪里
?

Vue3.x 改用 Proxy 替代 Object.defineProperty

原因在于 Object.defineProperty 本身存在的一些問題:

Object.defineProperty 只能劫持對(duì)象屬性的 getter 和 setter 方法。
Object.definedProperty 不支持?jǐn)?shù)組(可以監(jiān)聽數(shù)組,不過數(shù)組方法無法監(jiān)聽自己重寫),更準(zhǔn)確的說是不支持?jǐn)?shù)組的各種 API(所以 Vue 重寫了數(shù)組方法。
而相比 Object.defineProperty,Proxy 的優(yōu)點(diǎn)在于:

Proxy 是直接代理劫持整個(gè)對(duì)象。
Proxy 可以直接監(jiān)聽對(duì)象和數(shù)組的變化,并且有多達(dá) 13 種攔截方法。
目前,Object.definedProperty 唯一比 Proxy 好的一點(diǎn)就是兼容性,不過 Proxy 新標(biāo)準(zhǔn)也受到瀏覽器廠商重點(diǎn)持續(xù)的性能優(yōu)化當(dāng)中。

25. Vue 與 Angular 以及 React 的區(qū)別是什么?
?

這種題目是開放性題目,一般是面試過程中面試官口頭來提問,不太可能出現(xiàn)在筆試試卷里面。

關(guān)于 Vue 和其他框架的不同,官方專門寫了一篇文檔,從性能、體積、靈活性等多個(gè)方面來進(jìn)行了說明。

詳細(xì)可以參閱:https://cn.vuejs.org/v2/guide/comparison.html

建議面試前通讀一遍該篇文檔,然后進(jìn)行適當(dāng)?shù)目偨Y(jié)。

26. 說一下 watch 與 computed 的區(qū)別是什么?以及他們的使用場(chǎng)景分別是什么?
?

區(qū)別:

都是觀察數(shù)據(jù)變化的(相同)
計(jì)算屬性將會(huì)混入到 vue 的實(shí)例中,所以需要監(jiān)聽自定義變量;watch 監(jiān)聽 data 、props 里面數(shù)據(jù)的變化;
computed 有緩存,它依賴的值變了才會(huì)重新計(jì)算,watch 沒有;
watch 支持異步,computed 不支持;
watch 是一對(duì)多(監(jiān)聽某一個(gè)值變化,執(zhí)行對(duì)應(yīng)操作);computed 是多對(duì)一(監(jiān)聽屬性依賴于其他屬性)
watch 監(jiān)聽函數(shù)接收兩個(gè)參數(shù),第一個(gè)是最新值,第二個(gè)是輸入之前的值;
computed 屬性是函數(shù)時(shí),都有 get 和 set 方法,默認(rèn)走 get 方法,get 必須有返回值(return)
watch 的 參數(shù):

deep:深度監(jiān)聽
immediate :組件加載立即觸發(fā)回調(diào)函數(shù)執(zhí)行
computed 緩存原理:

conputed本質(zhì)是一個(gè)惰性的觀察者;當(dāng)計(jì)算數(shù)據(jù)存在于 data 或者 props里時(shí)會(huì)被警告;

vue 初次運(yùn)行會(huì)對(duì) computed 屬性做初始化處理(initComputed),初始化的時(shí)候會(huì)對(duì)每一個(gè) computed 屬性用 watcher 包裝起來 ,這里面會(huì)生成一個(gè) dirty 屬性值為 true;然后執(zhí)行 defineComputed 函數(shù)來計(jì)算,計(jì)算之后會(huì)將 dirty 值變?yōu)?false,這里會(huì)根據(jù) dirty 值來判斷是否需要重新計(jì)算;如果屬性依賴的數(shù)據(jù)發(fā)生變化,computed 的 watcher 會(huì)把 dirty 變?yōu)?true,這樣就會(huì)重新計(jì)算 computed 屬性的值。

27. scoped 是如何實(shí)現(xiàn)樣式穿透的?
?

首先說一下什么場(chǎng)景下需要 scoped 樣式穿透。

在很多項(xiàng)目中,會(huì)出現(xiàn)這么一種情況,即:引用了第三方組件,需要在組件中局部修改第三方組件的樣式,而又不想去除 scoped 屬性造成組件之間的樣式污染。此時(shí)只能通過特殊的方式,穿透 scoped。

有三種常用的方法來實(shí)現(xiàn)樣式穿透。

方法一

使用 ::v-deep 操作符( >>> 的別名)

如果希望 scoped 樣式中的一個(gè)選擇器能夠作用得“更深”,例如影響子組件,可以使用 >>> 操作符:

<style scoped>
? ? .a >>> .b { /* ... */ }
</style>

上述代碼將會(huì)編譯成:

.a[data-v-f3f3eg9] .b { /* ... */ }
后面的類名沒有 data 屬性,所以能選到子組件里面的類名。

有些像 Sass 之類的預(yù)處理器無法正確解析 >>>,所以需要使用 ::v-deep 操作符來代替。

方法二

定義一個(gè)含有 scoped 屬性的 style 標(biāo)簽之外,再定義一個(gè)不含有 scoped 屬性的 style 標(biāo)簽,即在一個(gè) vue 組件中定義一個(gè)全局的 style 標(biāo)簽,一個(gè)含有作用域的 style 標(biāo)簽:

<style>
/* global styles */
</style>

<style scoped>
/* local styles */
</style>
此時(shí),我們只需要將修改第三方樣式的 css 寫在第一個(gè) style 中即可。

方法三

上面的方法一需要單獨(dú)書寫一個(gè)不含有 scoped 屬性的 style 標(biāo)簽,可能會(huì)造成全局樣式的污染。

更推薦的方式是在組件的外層 DOM 上添加唯一的 class 來區(qū)分不同組件,在書寫樣式時(shí)就可以正常針對(duì)針對(duì)這部分 DOM 書寫樣式。

28. 說一下 ref 的作用是什么?
?

ref 的作用是被用來給元素或子組件注冊(cè)引用信息。引用信息將會(huì)注冊(cè)在父組件的 $refs 對(duì)象上。其特點(diǎn)是:

如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素
如果用在子組件上,引用就指向組件實(shí)例
所以常見的使用場(chǎng)景有:

基本用法,本頁面獲取 DOM 元素
獲取子組件中的 data
調(diào)用子組件中的方法


29. 說一下你知道的 vue 修飾符都有哪些?
?

在 vue 中修飾符可以分為 3 類:

事件修飾符
按鍵修飾符
表單修飾符
事件修飾符

在事件處理程序中調(diào)用 event.preventDefault 或 event.stopPropagation 方法是非常常見的需求。盡管可以在 methods 中輕松實(shí)現(xiàn)這點(diǎn),但更好的方式是:methods 只有純粹的數(shù)據(jù)邏輯,而不是去處理 DOM 事件細(xì)節(jié)。

為了解決這個(gè)問題,vue 為 v-on 提供了事件修飾符。通過由點(diǎn) . 表示的指令后綴來調(diào)用修飾符。

常見的事件修飾符如下:

.stop:阻止冒泡。
.prevent:阻止默認(rèn)事件。
.capture:使用事件捕獲模式。
.self:只在當(dāng)前元素本身觸發(fā)。
.once:只觸發(fā)一次。
.passive:默認(rèn)行為將會(huì)立即觸發(fā)。
按鍵修飾符

除了事件修飾符以外,在 vue 中還提供了有鼠標(biāo)修飾符,鍵值修飾符,系統(tǒng)修飾符等功能。

.left:左鍵
.right:右鍵
.middle:滾輪
.enter:回車
.tab:制表鍵
.delete:捕獲 “刪除” 和 “退格” 鍵
.esc:返回
.space:空格
.up:上
.down:下
.left:左
.right:右
.ctrl:ctrl 鍵
.alt:alt 鍵
.shift:shift 鍵
.meta:meta 鍵
表單修飾符

vue 同樣也為表單控件也提供了修飾符,常見的有 .lazy、.number 和 .trim。

.lazy:在文本框失去焦點(diǎn)時(shí)才會(huì)渲染
.number:將文本框中所輸入的內(nèi)容轉(zhuǎn)換為number類型
.trim:可以自動(dòng)過濾輸入首尾的空格


30. 如何實(shí)現(xiàn) vue 項(xiàng)目中的性能優(yōu)化?
?

編碼階段

盡量減少 data 中的數(shù)據(jù),data 中的數(shù)據(jù)都會(huì)增加 getter 和 setter,會(huì)收集對(duì)應(yīng)的 watcher
v-if 和 v-for 不能連用
如果需要使用 v-for 給每項(xiàng)元素綁定事件時(shí)使用事件代理
SPA 頁面采用 keep-alive 緩存組件
在更多的情況下,使用 v-if 替代 v-show
key 保證唯一
使用路由懶加載、異步組件
防抖、節(jié)流
第三方模塊按需導(dǎo)入
長(zhǎng)列表滾動(dòng)到可視區(qū)域動(dòng)態(tài)加載
圖片懶加載
SEO 優(yōu)化

預(yù)渲染
服務(wù)端渲染 SSR
打包優(yōu)化

壓縮代碼
Tree Shaking/Scope Hoisting
使用 cdn 加載第三方模塊
多線程打包 happypack
splitChunks 抽離公共文件
sourceMap 優(yōu)化
用戶體驗(yàn)

骨架屏
PWA
還可以使用緩存(客戶端緩存、服務(wù)端緩存)優(yōu)化、服務(wù)端開啟 gzip 壓縮等。

31. Vue.extend 和 Vue.component 的區(qū)別是什么?
?

Vue.extend 用于創(chuàng)建一個(gè)基于 Vue 構(gòu)造函數(shù)的“子類”,其參數(shù)應(yīng)為一個(gè)包含組件選項(xiàng)的對(duì)象。

Vue.component 用來注冊(cè)全局組件。

32. vue 中的 spa 應(yīng)用如何優(yōu)化首屏加載速度?
?

優(yōu)化首屏加載可以從這幾個(gè)方面開始:

請(qǐng)求優(yōu)化:CDN 將第三方的類庫放到 CDN 上,能夠大幅度減少生產(chǎn)環(huán)境中的項(xiàng)目體積,另外 CDN 能夠?qū)崟r(shí)地根據(jù)網(wǎng)絡(luò)流量和各節(jié)點(diǎn)的連接、負(fù)載狀況以及到用戶的距離和響應(yīng)時(shí)間等綜合信息將用戶的請(qǐng)求重新導(dǎo)向離用戶最近的服務(wù)節(jié)點(diǎn)上。
緩存:將長(zhǎng)時(shí)間不會(huì)改變的第三方類庫或者靜態(tài)資源設(shè)置為強(qiáng)緩存,將 max-age 設(shè)置為一個(gè)非常長(zhǎng)的時(shí)間,再將訪問路徑加上哈希達(dá)到哈希值變了以后保證獲取到最新資源,好的緩存策略有助于減輕服務(wù)器的壓力,并且顯著的提升用戶的體驗(yàn)
gzip:開啟 gzip 壓縮,通常開啟 gzip 壓縮能夠有效的縮小傳輸資源的大小。
http2:如果系統(tǒng)首屏同一時(shí)間需要加載的靜態(tài)資源非常多,但是瀏覽器對(duì)同域名的 tcp 連接數(shù)量是有限制的(chrome 為 6 個(gè))超過規(guī)定數(shù)量的 tcp 連接,則必須要等到之前的請(qǐng)求收到響應(yīng)后才能繼續(xù)發(fā)送,而 http2 則可以在多個(gè) tcp 連接中并發(fā)多個(gè)請(qǐng)求沒有限制,在一些網(wǎng)絡(luò)較差的環(huán)境開啟 http2 性能提升尤為明顯。
懶加載:當(dāng) url 匹配到相應(yīng)的路徑時(shí),通過 import 動(dòng)態(tài)加載頁面組件,這樣首屏的代碼量會(huì)大幅減少,webpack 會(huì)把動(dòng)態(tài)加載的頁面組件分離成單獨(dú)的一個(gè) chunk.js 文件
預(yù)渲染:由于瀏覽器在渲染出頁面之前,需要先加載和解析相應(yīng)的 html、css 和 js 文件,為此會(huì)有一段白屏的時(shí)間,可以添加loading,或者骨架屏幕盡可能的減少白屏對(duì)用戶的影響體積優(yōu)化
合理使用第三方庫:對(duì)于一些第三方 ui 框架、類庫,盡量使用按需加載,減少打包體積
使用可視化工具分析打包后的模塊體積:webpack-bundle- analyzer 這個(gè)插件在每次打包后能夠更加直觀的分析打包后模塊的體積,再對(duì)其中比較大的模塊進(jìn)行優(yōu)化
提高代碼使用率:利用代碼分割,將腳本中無需立即調(diào)用的代碼在代碼構(gòu)建時(shí)轉(zhuǎn)變?yōu)楫惒郊虞d的過程
封裝:構(gòu)建良好的項(xiàng)目架構(gòu),按照項(xiàng)目需求就行全局組件,插件,過濾器,指令,utils 等做一 些公共封裝,可以有效減少我們的代碼量,而且更容易維護(hù)資源優(yōu)化
圖片懶加載:使用圖片懶加載可以優(yōu)化同一時(shí)間減少 http 請(qǐng)求開銷,避免顯示圖片導(dǎo)致的畫面抖動(dòng),提高用戶體驗(yàn)
使用 svg 圖標(biāo):相對(duì)于用一張圖片來表示圖標(biāo),svg 擁有更好的圖片質(zhì)量,體積更小,并且不需要開啟額外的 http 請(qǐng)求
壓縮圖片:可以使用 image-webpack-loader,在用戶肉眼分辨不清的情況下一定程度上壓縮圖片


33. 移動(dòng)端如何實(shí)現(xiàn)一個(gè)比較友好的 header 組件
?

Header 一般分為左、中、右三個(gè)部分,分為三個(gè)區(qū)域來設(shè)計(jì),中間為主標(biāo)題,每個(gè)頁面的標(biāo)題肯定不同,所以可以通過 vue props的方式做成可配置對(duì)外進(jìn)行暴露,左側(cè)大部分頁面可能都是回退按鈕,但是樣式和內(nèi)容不盡相同,右側(cè)一般都是具有功能性的操作按鈕,所以左右兩側(cè)可以通過 vue slot 插槽的方式對(duì)外暴露以實(shí)現(xiàn)多樣化,同時(shí)也可以提供 default slot 默認(rèn)插槽來統(tǒng)一頁面風(fēng)格。

34. 既然 Vue 通過數(shù)據(jù)劫持可以精準(zhǔn)探測(cè)數(shù)據(jù)變化,為什么還需要虛擬 DOM 進(jìn)行 diff 監(jiān)測(cè)差異 ?
?

現(xiàn)代前端框架有兩種方式偵測(cè)變化,一種是 pull,一種是 push。

pull

其代表為 React,我們可以回憶一下 React 是如何偵測(cè)到變化的。

我們通常會(huì)用 setState API 顯式更新,然后 React 會(huì)進(jìn)行一層層的 Virtual Dom Diff 操作找出差異,然后 Patch 到 DOM 上,React 從一開始就不知道到底是哪發(fā)生了變化,只是知道「有變化了」,然后再進(jìn)行比較暴力的 Diff 操作查找「哪發(fā)生變化了」,另外一個(gè)代表就是 Angular 的臟檢查操作。

push

Vue 的響應(yīng)式系統(tǒng)則是 push 的代表,當(dāng) Vue 程序初始化的時(shí)候就會(huì)對(duì)數(shù)據(jù) data 進(jìn)行依賴的收集,一但數(shù)據(jù)發(fā)生變化,響應(yīng)式系統(tǒng)就會(huì)立刻得知,因此 Vue 是一開始就知道是「在哪發(fā)生變化了」

但是這又會(huì)產(chǎn)生一個(gè)問題,通常綁定一個(gè)數(shù)據(jù)就需要一個(gè) Watcher,一但我們的綁定細(xì)粒度過高就會(huì)產(chǎn)生大量的 Watcher,這會(huì)帶來內(nèi)存以及依賴追蹤的開銷,而細(xì)粒度過低會(huì)無法精準(zhǔn)偵測(cè)變化,因此 Vue 的設(shè)計(jì)是選擇中等細(xì)粒度的方案,在組件級(jí)別進(jìn)行 push 偵測(cè)的方式,也就是那套響應(yīng)式系統(tǒng)。

通常我們會(huì)第一時(shí)間偵測(cè)到發(fā)生變化的組件,然后在組件內(nèi)部進(jìn)行 Virtual Dom Diff 獲取更加具體的差異,而 Virtual Dom Diff 則是 pull 操作,Vue 是 push + pull 結(jié)合的方式進(jìn)行變化偵測(cè)的。

35. Vue 為什么沒有類似于 React 中 shouldComponentUpdate 的生命周期?
?

根本原因是 Vue 與 React 的變化偵測(cè)方式有所不同

React 是 pull 的方式偵測(cè)變化,當(dāng) React 知道發(fā)生變化后,會(huì)使用 Virtual Dom Diff 進(jìn)行差異檢測(cè),但是很多組件實(shí)際上是肯定不會(huì)發(fā)生變化的,這個(gè)時(shí)候需要用 shouldComponentUpdate 進(jìn)行手動(dòng)操作來減少 diff,從而提高程序整體的性能。

Vue 是 pull+push 的方式偵測(cè)變化的,在一開始就知道那個(gè)組件發(fā)生了變化,因此在 push 的階段并不需要手動(dòng)控制 diff,而組件內(nèi)部采用的 diff 方式實(shí)際上是可以引入類似于 shouldComponentUpdate 相關(guān)生命周期的,但是通常合理大小的組件不會(huì)有過量的 diff,手動(dòng)優(yōu)化的價(jià)值有限,因此目前 Vue 并沒有考慮引入 shouldComponentUpdate 這種手動(dòng)優(yōu)化的生命周期。

36. Vue 中的 Key 的作用是什么?

key 的作用主要是為了高效的更新虛擬 DOM。另外 vue 中在使用相同標(biāo)簽名元素的過渡切換時(shí),也會(huì)使用到 key 屬性,其目的也是為了讓 vue 可以區(qū)分它們,否則 vue 只會(huì)替換其內(nèi)部屬性而不會(huì)觸發(fā)過渡效果。

解析:

其實(shí)不只是 vue,react 中在執(zhí)行列表渲染時(shí)也會(huì)要求給每個(gè)組件添加上 key 這個(gè)屬性。

要解釋 key 的作用,不得不先介紹一下虛擬 DOM 的 Diff 算法了。

我們知道,vue 和 react 都實(shí)現(xiàn)了一套虛擬 DOM,使我們可以不直接操作 DOM 元素,只操作數(shù)據(jù)便可以重新渲染頁面。而隱藏在背后的原理便是其高效的 Diff 算法。

vue 和 react 的虛擬 DOM 的 Diff 算法大致相同,其核心有以下兩點(diǎn):

兩個(gè)相同的組件產(chǎn)生類似的 DOM 結(jié)構(gòu),不同的組件產(chǎn)生不同的 DOM 結(jié)構(gòu)。

同一層級(jí)的一組節(jié)點(diǎn),他們可以通過唯一的 id 進(jìn)行區(qū)分。

基于以上這兩點(diǎn),使得虛擬 DOM 的 Diff 算法的復(fù)雜度從 O(n^3) 降到了 O(n)。


當(dāng)頁面的數(shù)據(jù)發(fā)生變化時(shí),Diff 算法只會(huì)比較同一層級(jí)的節(jié)點(diǎn):

如果節(jié)點(diǎn)類型不同,直接干掉前面的節(jié)點(diǎn),再創(chuàng)建并插入新的節(jié)點(diǎn),不會(huì)再比較這個(gè)節(jié)點(diǎn)以后的子節(jié)點(diǎn)了。
如果節(jié)點(diǎn)類型相同,則會(huì)重新設(shè)置該節(jié)點(diǎn)的屬性,從而實(shí)現(xiàn)節(jié)點(diǎn)的更新。
當(dāng)某一層有很多相同的節(jié)點(diǎn)時(shí),也就是列表節(jié)點(diǎn)時(shí),Diff 算法的更新過程默認(rèn)情況下也是遵循以上原則。

比如一下這個(gè)情況:

我們希望可以在 B 和 C 之間加一個(gè) F,Diff 算法默認(rèn)執(zhí)行起來是這樣的:

即把 C 更新成 F,D 更新成 C,E 更新成 D,最后再插入 E

是不是很沒有效率?

所以我們需要使用 key 來給每個(gè)節(jié)點(diǎn)做一個(gè)唯一標(biāo)識(shí),Diff 算法就可以正確的識(shí)別此節(jié)點(diǎn),找到正確的位置區(qū)插入新的節(jié)點(diǎn)。

37. 你的接口請(qǐng)求一般放在哪個(gè)生命周期中?為什么要這樣做?

接口請(qǐng)求可以放在鉤子函數(shù) created、beforeMount、mounted 中進(jìn)行調(diào)用,因?yàn)樵谶@三個(gè)鉤子函數(shù)中,data 已經(jīng)創(chuàng)建,可以將服務(wù)端端返回的數(shù)據(jù)進(jìn)行賦值。

但是推薦在 created 鉤子函數(shù)中調(diào)用異步請(qǐng)求,因?yàn)樵?created 鉤子函數(shù)中調(diào)用異步請(qǐng)求有以下優(yōu)點(diǎn):

能更快獲取到服務(wù)端數(shù)據(jù),減少頁面 loading 時(shí)間
SSR 不支持 beforeMount 、mounted 鉤子函數(shù),所以放在 created 中有助于代碼的一致性
created 是在模板渲染成 html 前調(diào)用,即通常初始化某些屬性值,然后再渲染成視圖。如果在 mounted 鉤子函數(shù)中請(qǐng)求數(shù)據(jù)可能導(dǎo)致頁面閃屏問題


38. 說一下你對(duì) vue 事件綁定原理的理解?
?

vue 中的事件綁定是有兩種,一種是原生的事件綁定,另一種是組件的事件綁定。

原生的事件綁定在普通元素上是通過 @click 進(jìn)行綁定,在組件上是通過 @click.native 進(jìn)行綁定,組件中的 nativeOn 是等價(jià)于 on 的。組件的事件綁定的 @click 是 vue 中自定義的 $on 方法來實(shí)現(xiàn)的,必須有 $emit 才可以觸發(fā)。

原生事件綁定原理

在 runtime下的patch.js中createPatchFunction執(zhí)行了之后再賦值給patch。

createPatchFunction方法有兩個(gè)參數(shù),分別是nodeOps存放操作dom節(jié)點(diǎn)的方法和modules,modules是有兩個(gè)數(shù)組拼接起來的,modules拼接完的數(shù)組中有一個(gè)元素就是events,事件添加就發(fā)生在這里。

events元素關(guān)聯(lián)的就是events.js文件,在events中有一個(gè)updateDOMListeners方法,在events文件的結(jié)尾導(dǎo)出了一個(gè)對(duì)象,然后對(duì)象有一個(gè)屬性叫做create,這個(gè)屬性關(guān)聯(lián)的就是updateDOMListeners方法。

在執(zhí)行createPatchFunction方法時(shí),就會(huì)將這兩個(gè)參數(shù)傳入,在createPatchFunction方法中接收了一個(gè)參數(shù)backend,在該方法中一開始進(jìn)行backend的解構(gòu),就是上面的nodeOps和modules參數(shù),解構(gòu)完之后進(jìn)入for循環(huán)。

在createPatchFunction開頭定義了一個(gè)cbs對(duì)象。for循環(huán)遍歷一個(gè)叫hooks的數(shù)組。hooks是文件一開頭定義的一個(gè)數(shù)組,其中包括有create,for循環(huán)就是在cbs上定義一系列和hooks元素相同的屬性,然后鍵值是一個(gè)數(shù)組,然后數(shù)組內(nèi)容是modules里面的一些內(nèi)容。這時(shí)就把events文件中導(dǎo)出來的create屬性放在了cbs上。

當(dāng)我們進(jìn)入首次渲染的時(shí)候,會(huì)執(zhí)行到patch函數(shù)里面的createElm方法,這個(gè)方法中就會(huì)調(diào)用invokeCreateHooks函數(shù),用來處理事件系統(tǒng),這里就是真正準(zhǔn)備進(jìn)行原生事件綁定的入口。invokeCreateHooks方法中,遍歷了cbs.create數(shù)組里面的內(nèi)容。然后把cbs.create里面的函數(shù)全部都執(zhí)行一次,在cbs.create其中一個(gè)函數(shù)就是updateDOMListeners。

updateDOMListeners就是用來添加事件的方法,在這方法中會(huì)根據(jù)vnode判斷是否有定義一個(gè)點(diǎn)擊事件。如果沒有點(diǎn)擊事件就return。有的話就繼續(xù)執(zhí)行,給on進(jìn)行賦值,然后進(jìn)行一些賦值操作,將vnode.elm賦值給target,elm這個(gè)屬性就是指向vnode所對(duì)應(yīng)的真實(shí)dom節(jié)點(diǎn),這里就是把我們要綁定事件的dom結(jié)點(diǎn)進(jìn)行緩存,接下來執(zhí)行updateListeners方法。在接下來執(zhí)行updateListeners方法中調(diào)用了一個(gè)add的方法,然后在app方法中通過原生addEventListener把事件綁定到dom上。

組件事件綁定原理

在組件實(shí)例初始化會(huì)調(diào)用initMixin方法中的Vue.prototype._init,在init函數(shù)中,會(huì)通過initInternalComponent方法初始化組件信息,將自定義的組件事件放到_parentListeners上,下來就會(huì)調(diào)用initEvents來初始化組件事件,在initEvents中會(huì)實(shí)例上添加一個(gè) _event對(duì)象,用于保存自定義事件,然后獲取到 父組件給 子組件綁定的自定義事件,也就是剛才在初始化組件信息的時(shí)候?qū)⒆远x的組件事件放在了_parentListeners上,這時(shí)候vm.$options._parentListeners就是自定義的事件。

最后進(jìn)行判斷,如果有自定義的組件事件就執(zhí)行updateComponentListeners方法進(jìn)行事件綁定,在updateComponentListeners方法中會(huì)調(diào)用updateListeners方法,并傳傳一個(gè)add方法進(jìn)行執(zhí)行,這個(gè)add方法里就是$on方法。

39. 說一下 vue 模版編譯的原理是什么
?

簡(jiǎn)單說,Vue 的編譯過程就是將 template 轉(zhuǎn)化為 render 函數(shù)的過程。會(huì)經(jīng)歷以下階段:

生成 AST 樹
優(yōu)化
codegen
首先解析模版,生成 AST 語法樹(一種用 JavaScript 對(duì)象的形式來描述整個(gè)模板)。 使用大量的正則表達(dá)式對(duì)模板進(jìn)行解析,遇到標(biāo)簽、文本的時(shí)候都會(huì)執(zhí)行對(duì)應(yīng)的鉤子進(jìn)行相關(guān)處理。

Vue 的數(shù)據(jù)是響應(yīng)式的,但其實(shí)模板中并不是所有的數(shù)據(jù)都是響應(yīng)式的。有一些數(shù)據(jù)首次渲染后就不會(huì)再變化,對(duì)應(yīng)的 DOM 也不會(huì)變化。那么優(yōu)化過程就是深度遍歷 AST 樹,按照相關(guān)條件對(duì)樹節(jié)點(diǎn)進(jìn)行標(biāo)記。這些被標(biāo)記的節(jié)點(diǎn)(靜態(tài)節(jié)點(diǎn))我們就可以跳過對(duì)它們的比對(duì),對(duì)運(yùn)行時(shí)的模板起到很大的優(yōu)化作用。

編譯的最后一步是將優(yōu)化后的 AST 樹轉(zhuǎn)換為可執(zhí)行的代碼。

可以參閱前面第 22 題。

40. delete 和 Vue.delete 刪除數(shù)組的區(qū)別是什么?
?

delete 只是被刪除的元素變成了 empty/undefined 其他的元素的鍵值還是不變。
Vue.delete 是直接將元素從數(shù)組中完全刪除,改變了數(shù)組其他元素的鍵值。

41. v-on 可以實(shí)現(xiàn)監(jiān)聽多個(gè)方法么?
?

可以監(jiān)聽多個(gè)方法。關(guān)于監(jiān)聽多個(gè)方法提供了幾種不同的寫法:

寫法一:<div v-on="{ 事件類型: 事件處理函數(shù), 事件類型: 事件處理函數(shù) }"></div>
寫法二:<div @事件類型=“事件處理函數(shù)” @事件類型=“事件處理函數(shù)”></div>
寫法三:在一個(gè)事件里面書寫多個(gè)事件處理函數(shù)
<div @事件類型=“事件處理函數(shù)1,事件處理函數(shù)2”></div>
寫法四:在事件處理函數(shù)內(nèi)部調(diào)用其他的函數(shù)
示例代碼如下:

<template>
? <div>
? ? <!-- v-on在vue2.x中測(cè)試,以下兩種均可-->
? ? <button v-on="{ mouseenter: onEnter, mouseleave: onLeave }">
? ? ? 鼠標(biāo)進(jìn)來1
? ? </button>
? ? <button @mouseenter="onEnter" @mouseleave="onLeave">鼠標(biāo)進(jìn)來2</button>

? ? <!-- 一個(gè)事件綁定多個(gè)函數(shù),按順序執(zhí)行,這里分隔函數(shù)可以用逗號(hào)也可以用分號(hào)-->
? ? <button @click="a(), b()">點(diǎn)我ab</button>
? ? <button @click="one()">點(diǎn)我onetwothree</button>
? </div>
</template>
<script>
export default {
? methods: {
? ? //這里是es6對(duì)象里函數(shù)寫法
? ? a() {
? ? ? console.log("a");
? ? },
? ? b() {
? ? ? console.log("b");
? ? },
? ? one() {
? ? ? console.log("one");
? ? ? this.two();
? ? ? this.three();
? ? },
? ? two() {
? ? ? console.log("two");
? ? },
? ? three() {
? ? ? console.log("three");
? ? },
? ? onEnter() {
? ? ? console.log("mouse enter");
? ? },
? ? onLeave() {
? ? ? console.log("mouse leave");
? ? },
? },
};
</script>



42. vue 的數(shù)據(jù)為什么頻繁變化但只會(huì)更新一次?
?

這是因?yàn)?vue 的 DOM 更新是一個(gè)異步操作,在數(shù)據(jù)更新后會(huì)首先被 set 鉤子監(jiān)聽到,但是不會(huì)馬上執(zhí)行 DOM 更新,而是在下一輪循環(huán)中執(zhí)行更新。

具體實(shí)現(xiàn)是 vue 中實(shí)現(xiàn)了一個(gè) queue 隊(duì)列用于存放本次事件循環(huán)中的所有 watcher 更新,并且同一個(gè) watcher 的更新只會(huì)被推入隊(duì)列一次,并在本輪事件循環(huán)的微任務(wù)執(zhí)行結(jié)束后執(zhí)行此更新(UI Render 階段),這就是 DOM 只會(huì)更新一次的原因。

這種在緩沖時(shí)去除重復(fù)數(shù)據(jù)對(duì)于避免不必要的計(jì)算和 DOM 操作是非常重要的。然后,在下一個(gè)的事件循環(huán)“tick”中,vue 刷新隊(duì)列并執(zhí)行實(shí)際 (已去重的) 工作。vue 在內(nèi)部對(duì)異步隊(duì)列嘗試使用原生的 Promise.then、MutationObserver 和 setImmediate,如果執(zhí)行環(huán)境不支持,則會(huì)采用 setTimeout(fn, 0) 代替。

43. 說一下 vue 中 computed 和 methods 的區(qū)別是什么?
?

首先從表現(xiàn)形式上面來看, computed 和 methods 的區(qū)別大致有下面 4 點(diǎn):

在使用時(shí),computed 當(dāng)做屬性使用,而 methods 則當(dāng)做方法調(diào)用
computed 可以具有 getter 和 setter,因此可以賦值,而 methods 不行
computed 無法接收多個(gè)參數(shù),而 methods 可以
computed 具有緩存,而 methods 沒有
而如果從底層來看的話, computed 和 methods 在底層實(shí)現(xiàn)上面還有很大的區(qū)別。

vue 對(duì) methods 的處理比較簡(jiǎn)單,只需要遍歷 methods 配置中的每個(gè)屬性,將其對(duì)應(yīng)的函數(shù)使用 bind 綁定當(dāng)前組件實(shí)例后復(fù)制其引用到組件實(shí)例中即可

而 vue 對(duì) computed 的處理會(huì)稍微復(fù)雜一些。

具體可以參閱前面第 21 題。

44. 在 Vue 中要獲取當(dāng)前時(shí)間你會(huì)放到 computed 還是 methods 里?(抖音直播)
?

放在 computed 里面。因?yàn)?computed 只有在它的相關(guān)依賴發(fā)生改變時(shí)才會(huì)重新求值。相比而言,方法只要發(fā)生重新渲染,methods 調(diào)用總會(huì)執(zhí)行所有函數(shù)。

45. 在給 vue 中的元素設(shè)置 key 值時(shí)可以使用 Math 的 random 方法么?
?

random 是生成隨機(jī)數(shù),有一定概率多個(gè) item 會(huì)生成相同的值,不能保證唯一。

如果是根據(jù)數(shù)據(jù)來生成 item,數(shù)據(jù)具有 id 屬性,那么就可以使用 id 來作為 key。

如果不是根據(jù)數(shù)據(jù)生成 item,那么最好的方式就是使用時(shí)間戳來作為 key?;蛘呤褂弥T如 uuid 之類的庫來生成唯一的 id。

46. 插槽與作用域插槽的區(qū)別是什么?

插槽的作用是子組件提供了可替換模板,父組件可以更換模板的內(nèi)容。

作用域插槽給了子組件將數(shù)據(jù)返給父組件的能力,子組件一樣可以復(fù)用,同時(shí)父組件也可以重新組織內(nèi)容和樣式。

47. vue 中相同邏輯如何進(jìn)行抽離?

可以使用 vue 里面的混入(mixin)技術(shù)?;烊耄╩ixin)提供了一種非常靈活的方式,來將 vue 中相同的業(yè)務(wù)邏輯進(jìn)行抽離。

例如:

在 data 中有很多是公用數(shù)據(jù)
引用封裝好的組件也都是一樣的
methods、watch、computed 中也都有大量的重復(fù)代碼
當(dāng)然這個(gè)時(shí)候可以將所有的代碼重復(fù)去寫來實(shí)現(xiàn)功能,但是我們并不不推薦使用這種方式,無論是工作量、工作效率和后期維護(hù)來說都是不建議的,這個(gè)時(shí)候 mixin 就可以大展身手了。

一個(gè)混入對(duì)象可以包含任意組件選項(xiàng)。當(dāng)組件使用混入對(duì)象時(shí),所有混入對(duì)象的選項(xiàng)將被“混合”進(jìn)入該組件本身的選項(xiàng)。說白了就是給每個(gè)生命周期,函數(shù)等等中間加入一些公共邏輯。

混入技術(shù)特點(diǎn)

當(dāng)組件和混入對(duì)象含有同名選項(xiàng)時(shí),這些選項(xiàng)將以恰當(dāng)?shù)姆绞竭M(jìn)行“合并”。比如,數(shù)據(jù)對(duì)象在內(nèi)部會(huì)進(jìn)行遞歸合并,并在發(fā)生沖突時(shí)以組件數(shù)據(jù)優(yōu)先。
同名鉤子函數(shù)將合并為一個(gè)數(shù)組,因此都將被調(diào)用。另外,混入對(duì)象的鉤子將在組件自身鉤子之前調(diào)用。
值為對(duì)象的選項(xiàng),例如 methods、components 和 directives,將被合并為同一個(gè)對(duì)象。兩個(gè)對(duì)象鍵名沖突時(shí),取組件對(duì)象的鍵值對(duì)。


48. 如何監(jiān)聽 pushstate 和 replacestate 的變化呢?
?

History.replaceState 和 pushState 不會(huì)觸發(fā) popstate 事件,所以我們可以通過在方法中創(chuàng)建一個(gè)新的全局事件來實(shí)現(xiàn) pushstate 和 replacestate 變化的監(jiān)聽。

具體做法為:

var _wr = function(type) {
? var orig = history[type];
? return function() {
? ? ? var rv = orig.apply(this, arguments);
? ? ?var e = new Event(type);
? ? ? e.arguments = arguments;
? ? ? window.dispatchEvent(e);
? ? ? return rv;
? };
};
history.pushState = _wr('pushState');
history.replaceState = _wr('replaceState');

這樣就創(chuàng)建了 2 個(gè)全新的事件,事件名為 pushState 和 replaceState,我們就可以在全局監(jiān)聽:

window.addEventListener('replaceState', function(e) {
?console.log('THEY DID IT AGAIN! replaceState 111111');
});
window.addEventListener('pushState', function(e) {
?console.log('THEY DID IT AGAIN! pushState 2222222');
});

這樣就可以監(jiān)聽到 pushState 和 replaceState 行為。

49. 說一下 vue3.0 是如何變得更快的?
?

優(yōu)化 Diff 算法

相比 Vue 2,Vue 3 采用了更加優(yōu)化的渲染策略。去掉不必要的虛擬 DOM 樹遍歷和屬性比較,因?yàn)檫@在更新期間往往會(huì)產(chǎn)生最大的性能開銷。

這里有三個(gè)主要的優(yōu)化:

首先,在 DOM 樹級(jí)別。
在沒有動(dòng)態(tài)改變節(jié)點(diǎn)結(jié)構(gòu)的模板指令(例如 v-if 和 v-for)的情況下,節(jié)點(diǎn)結(jié)構(gòu)保持完全靜態(tài)。

當(dāng)更新節(jié)點(diǎn)時(shí),不再需要遞歸遍歷 DOM 樹。所有的動(dòng)態(tài)綁定部分將在一個(gè)平面數(shù)組中跟蹤。這種優(yōu)化通過將需要執(zhí)行的樹遍歷量減少一個(gè)數(shù)量級(jí)來規(guī)避虛擬 DOM 的大部分開銷。

其次,編譯器積極地檢測(cè)模板中的靜態(tài)節(jié)點(diǎn)、子樹甚至數(shù)據(jù)對(duì)象,并在生成的代碼中將它們提升到渲染函數(shù)之外。這樣可以避免在每次渲染時(shí)重新創(chuàng)建這些對(duì)象,從而大大提高內(nèi)存使用率并減少垃圾回收的頻率。

第三,在元素級(jí)別。

編譯器還根據(jù)需要執(zhí)行的更新類型,為每個(gè)具有動(dòng)態(tài)綁定的元素生成一個(gè)優(yōu)化標(biāo)志。

例如,具有動(dòng)態(tài)類綁定和許多靜態(tài)屬性的元素將收到一個(gè)標(biāo)志,提示只需要進(jìn)行類檢查。運(yùn)行時(shí)將獲取這些提示并采用專用的快速路徑。

綜合起來,這些技術(shù)大大改進(jìn)了渲染更新基準(zhǔn),Vue 3.0 有時(shí)占用的 CPU 時(shí)間不到 Vue 2 的十分之一。

體積變小

重寫后的 Vue 支持了 tree-shaking,像修剪樹葉一樣把不需要的東西給修剪掉,使 Vue 3.0 的體積更小。

需要的模塊才會(huì)打入到包里,優(yōu)化后的 Vue 3.0 的打包體積只有原來的一半(13kb)。哪怕把所有的功能都引入進(jìn)來也只有 23kb,依然比 Vue 2.x 更小。像 keep-alive、transition 甚至 v-for 等功能都可以按需引入。

并且 Vue 3.0 優(yōu)化了打包方法,使得打包后的 bundle 的體積也更小。

官方所給出的一份驚艷的數(shù)據(jù):打包大小減少 41%,初次渲染快 55%,更新快 133%,內(nèi)存使用減少 54%。

50. 說一說自定義指令有哪些生命周期?

?

自定義指令的生命周期,有 5 個(gè)事件鉤子,可以設(shè)置指令在某一個(gè)事件發(fā)生時(shí)的具體行為:

bind: 只調(diào)用一次,指令第一次綁定到元素時(shí)調(diào)用,用這個(gè)鉤子函數(shù)可以定義一個(gè)在綁定時(shí)執(zhí)行一次的初始化動(dòng)作。
inserted: 被綁定元素插入父節(jié)點(diǎn)時(shí)調(diào)用(父節(jié)點(diǎn)存在即可調(diào)用,不必存在于 document 中)。
update: 被綁定元素所在的模板更新時(shí)調(diào)用,而不論綁定值是否變化。通過比較更新前后的綁定值,可以忽略不必要的模板更新(詳細(xì)的鉤子函數(shù)參數(shù)見下)。
componentUpdated: 被綁定元素所在模板完成一次更新周期時(shí)調(diào)用。
unbind: 只調(diào)用一次, 指令與元素解綁時(shí)調(diào)用。
鉤子函數(shù)的參數(shù) (包括 el,binding,vnode,oldVnode)

el: 指令所綁定的元素,可以用來直接操作 DOM 。
binding: 一個(gè)對(duì)象,包含以下屬性:name: 指令名、value: 指令的綁定值、oldValue: 指令綁定的前一個(gè)值、expression: 綁定值的字符串形式、arg: 傳給指令的參數(shù)、modifiers: 一個(gè)包含修飾符的對(duì)象。
vnode: Vue 編譯生成的虛擬節(jié)點(diǎn)。
oldVnode: 上一個(gè)虛擬節(jié)點(diǎn),僅在 update 和 componentUpdated 鉤子中可用。


51. 說一說相比 vue3.x 對(duì)比 vue2.x 變化
?

源碼組織方式變化:使用 TS 重寫
支持 Composition API:基于函數(shù)的API,更加靈活組織組件邏輯(vue2用的是options api)
響應(yīng)式系統(tǒng)提升:Vue3中響應(yīng)式數(shù)據(jù)原理改成proxy,可監(jiān)聽動(dòng)態(tài)新增刪除屬性,以及數(shù)組變化
編譯優(yōu)化:vue2通過標(biāo)記靜態(tài)根節(jié)點(diǎn)優(yōu)化diff,Vue3 標(biāo)記和提升所有靜態(tài)根節(jié)點(diǎn),diff的時(shí)候只需要對(duì)比動(dòng)態(tài)節(jié)點(diǎn)內(nèi)容
打包體積優(yōu)化:移除了一些不常用的api(inline-template、filter)
生命周期的變化:使用setup代替了之前的beforeCreate和created
Vue3 的 template 模板支持多個(gè)根標(biāo)簽
Vuex狀態(tài)管理:創(chuàng)建實(shí)例的方式改變,Vue2為new Store , Vue3為createStore
Route 獲取頁面實(shí)例與路由信息:vue2通過this獲取router實(shí)例,vue3通過使用 getCurrentInstance/ userRoute和userRouter方法獲取當(dāng)前組件實(shí)例
Props 的使用變化:vue2 通過 this 獲取 props 里面的內(nèi)容,vue3 直接通過 props
父子組件傳值:vue3 在向父組件傳回?cái)?shù)據(jù)時(shí),如使用的自定義名稱,如 backData,則需要在 emits 中定義一下


52. vue 為什么采用異步渲染

因?yàn)槿绻徊捎卯惒礁拢敲疵看胃聰?shù)據(jù)都會(huì)對(duì)當(dāng)前組件進(jìn)行重新渲染;所以為了性能考慮,Vue 會(huì)在本輪數(shù)據(jù)更新后,再去異步更新視圖。

異步渲染的原理:

調(diào)用 notify( ) 方法,通知 watcher 進(jìn)行更新操作
依次調(diào)用 watcher 的 update 方法
對(duì) watcher 進(jìn)行去重操作(通過id)放到隊(duì)列里
執(zhí)行完后異步清空這個(gè)隊(duì)列,nextTick(flushSchedulerQueue)進(jìn)行批量更新操作


53. 組件中寫 name 選項(xiàng)有哪些好處
?

可以通過名字找到對(duì)應(yīng)的組件( 遞歸組件:組件自身調(diào)用自身 )
可以通過 name 屬性實(shí)現(xiàn)緩存功能(keep-alive)
可以通過 name 來識(shí)別組件(跨級(jí)組件通信時(shí)非常重要)
使用 vue-devtools 調(diào)試工具里顯示的組見名稱是由 vue 中組件 name 決定的文章來源地址http://www.zghlxwxcb.cn/news/detail-811729.html

到了這里,關(guān)于vue面試題集錦的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • Spark面試題集錦

    1、什么是Apache Spark?Spark是什么? 是基于內(nèi)存的分布式的大數(shù)據(jù)并行計(jì)算框架,可用于構(gòu)建大型的、低延遲的數(shù)據(jù)分析應(yīng)用程序。包含Spark core、Spark sql、Spark streaming 、Spark MLlib 、spark GraphX五個(gè)核心組件。 2、Spark的核心組件是什么? Spark Core:是其它組件的基礎(chǔ),spark的內(nèi)核

    2024年02月04日
    瀏覽(24)
  • 音視頻開發(fā)面試題集錦

    音視頻開發(fā)面試題集錦

    下面是 2022.06 月音視頻面試題集錦內(nèi)容的節(jié)選: 媒體封裝層是表示媒體數(shù)據(jù)是什么封裝格式的,比如 MP4、FLV。在這層信息里,通常會(huì)攜帶碼流編碼格式的信息。 拿 MP4 來說,我們可以根據(jù) Sample Description Box(moov/trak/mdia/minf/stbl/stsd) 中的信息來確定其封裝的碼流的編碼格式。

    2023年04月13日
    瀏覽(26)
  • 【數(shù)據(jù)結(jié)構(gòu)練習(xí)】鏈表面試題集錦一

    【數(shù)據(jù)結(jié)構(gòu)練習(xí)】鏈表面試題集錦一

    目錄 前言: 1. 刪除鏈表中所有值為key的節(jié)點(diǎn) ?方法一:正常刪除,頭結(jié)點(diǎn)另外討論 ?方法二:虛擬頭結(jié)點(diǎn)法 ?方法三:遞歸 2.反轉(zhuǎn)鏈表 ?方法一:雙指針迭代 ??方法二:遞歸法 3.鏈表的中間結(jié)點(diǎn)? ?方法:快慢指針法 4. 鏈表中倒數(shù)第k個(gè)結(jié)點(diǎn) ?方法:快慢指針方法 5.合并兩個(gè)

    2024年02月11日
    瀏覽(17)
  • 500道網(wǎng)絡(luò)安全面試題集錦(附答案)

    500道網(wǎng)絡(luò)安全面試題集錦(附答案)

    本篇文章內(nèi)容為網(wǎng)絡(luò)安全各個(gè)方向涉及的面試題,但是無論如何都無法覆蓋所有的面試問題,更多的還是希望由點(diǎn)達(dá)面,查漏補(bǔ)缺,然后祝各位前程似錦,都能找到自己滿意的工作! ? 攻擊者通過在web界面中嵌入惡意腳本(通常為js代碼),造成用戶在瀏覽網(wǎng)頁時(shí),控制用戶

    2024年02月15日
    瀏覽(26)
  • Java大廠常見1000道面試題集錦(一)

    Java大廠常見1000道面試題集錦(一)

    本系列為Java常見面試題集錦,持續(xù)更新中,包括筆試題和面試題, 建議收藏慢慢看 while(true){} 是一個(gè)無限循環(huán)的語句,它的作用是讓程序在執(zhí)行到該語句時(shí)不停地循環(huán)下去,直到程序被終止或者遇到 break、return 等跳出循環(huán)的語句。 無限循環(huán)的使用場(chǎng)景比較多,例如: 實(shí)現(xiàn)

    2024年02月06日
    瀏覽(56)
  • 找工作嗎?50道Python面試題集錦【附答案】

    找工作嗎?50道Python面試題集錦【附答案】

    嗨害大家好鴨!我是愛摸魚的芝士~ 希望能夠幫助你在今年的求職面試中脫穎而出, 找到一份高薪工作~ 這些面試題涉及Python基礎(chǔ)知識(shí)、Python編程、數(shù)據(jù)分析以及Python函數(shù)庫等多個(gè)方面。 提前預(yù)祝給這篇文章點(diǎn)贊收藏的友友們~ 拿到心中最滿意的那一份OFFER~ Q1、Python中的列表

    2023年04月18日
    瀏覽(26)
  • 前端2023最全面試題(javaScript、typeScript、vue2、vue3、html、css、uniapp、webpack、vite、react)

    答案:JavaScript中的閉包是一種函數(shù),它有權(quán)訪問其詞法環(huán)境的變量和其它函數(shù)。這意味著,即使其包含它的函數(shù)已經(jīng)執(zhí)行完畢,其詞法環(huán)境仍然存在,因此可以訪問其作用域內(nèi)的變量。 答案:回調(diào)函數(shù)是在某個(gè)特定事件之后執(zhí)行的函數(shù)。在JavaScript中,通常使用回調(diào)函數(shù)來處

    2024年02月06日
    瀏覽(35)
  • 在Vue2和Vue3中JSX的使用集錦

    在Vue2和Vue3中JSX的使用集錦

    有時(shí)候,我們使用渲染函數(shù)(render function)來抽象組件,而渲染函數(shù)使用Vue的h函數(shù)來編寫Dom元素相對(duì)template語法差別較大,體驗(yàn)不佳,這個(gè)時(shí)候就派 JSX 上場(chǎng)了。然而在Vue3中默認(rèn)是帶了JSX支持的,而在 Vue2 中使用 JSX,需要安裝并使用 Babel 插件: @vue/babel-preset-jsx @vue/babel-hel

    2024年02月09日
    瀏覽(52)
  • vue面試題_vue2和vue3的區(qū)別

    1、數(shù)據(jù)綁定原理不同 vue2:vue2的數(shù)據(jù)綁定是利用ES5的一個(gè)API:Object.definePropert() 對(duì)數(shù)據(jù)進(jìn)行劫持,結(jié)合發(fā)布訂閱模式的方式來實(shí)現(xiàn)的。 vue3:vue3中使用了ES6的Proxy API對(duì)數(shù)據(jù)代理。相比vue2.x,使用proxy的優(yōu)勢(shì)如下: defineProperty只能監(jiān)聽某個(gè)屬性,不能對(duì)全對(duì)象監(jiān)聽 可以省去for

    2024年02月10日
    瀏覽(26)
  • Vue經(jīng)典面試題:Vue2和Vue3的區(qū)別

    雙向綁定原理 vue2是用過ES5的一個(gè)API Object.defineProperty()對(duì)數(shù)據(jù)進(jìn)行劫持配合發(fā)布訂閱者模式的方式來實(shí)現(xiàn)的 Vue3是使用了ES6的proxyAPI對(duì)數(shù)據(jù)代理 Vue3支持碎片(Fragments) 就是說組件可以有多個(gè)根節(jié)點(diǎn) Composition API vue2采用選項(xiàng)類型API,而vue3采用 合成型API。代碼更加的簡(jiǎn)便整潔 生

    2023年04月19日
    瀏覽(24)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包