Vue面試題總結(一)
1.說說你對vue的理解
vue是一個漸進式的JavaScript框架,一套擁有自己規則的語法。旨在更好地組織與簡化Web開發。
vue的核心特性:
- 資料驅動檢視(MVVM)
MVVM:Model-View-ViewModel
Model:模型層,負責處理業務邏輯以及和伺服器端進行互動
View:檢視層:負責將資料模型轉化為UI展示出來,可以簡單的理解為HTML頁面
ViewModel:檢視模型層,用來連線Model和View,是Model和View之間的通訊橋樑
- 元件化
元件化:就是把圖形、非圖形的各種邏輯均抽象為一個統一的概念(元件)來實現開發的模式,在Vue
.vue
檔案都可以視為一個元件
元件化的優勢:
降低整個系統的耦合度,在保持介面不變的情況下,我們可以替換不同的元件快速完成需求,例如輸入框,可以替換為日曆、時間、範圍等元件作具體的實現
除錯方便,由於整個系統是通過元件組合起來的,在出現問題的時候,可以用排除法直接移除元件,或者根據報錯的元件快速定位問題,之所以能夠快速定位,是因為每個元件之間低耦合,職 責單一,所以邏輯會比分析整個系統要簡單
提高可維護性,由於每個元件的職責單一,並且元件在系統中是被複用的,所以對程式碼進行優化可獲得系統的整體升級
- 指令系統
指令 (Directives) 是帶有 v- 字首的特殊屬性作用:當表示式的值改變時,將其產生的連帶影響,響應式地作用於 DOM
常用指令:v-if v-for v-bind v-on v-model
2.computed和watch的區別
computed: 是一個計算屬性,依賴於其他的屬性值,其他依賴的屬性值發生變化後,computed的值才會發生改變,最主要的是具有快取的作用。
- 不支援非同步,當computed內有非同步操作時無效,無法監聽資料的變化
- 如果computed屬性值是函式,那麼預設會走get方法,函式的返回值就是屬性的屬性值;computed中的完整寫法(get和set兩個方法),給計算屬性變數賦值時用完整寫法,賦值用set(值),取值用get。
watch: 是一個偵聽器(監視器),可以偵聽data / computed屬性值的改變。
- 不支援快取
- watch支援非同步
- 監聽的函式接收兩個引數,第一個引數是最新的值(newVal)、第二個引數是輸入之前的值(oldVal)
- 深度偵聽:一般偵聽的是複雜資料型別,handler函式一般接收一個引數(指向同一個堆地址);需要深度偵聽的話,可以加上deep:true;需要即刻偵聽,加上immediate:true
兩者的應用場景:
當多個元素髮生變化導致一個結果進行變更的時候(多對一或一對一),可使用computed。
當一個元素髮生變化導致多個結果進行變更的時候(一對多),可使用watch。
3.談談你對vue生命週期的理解
Vue 例項有一個完整的生命週期,也就是建立前後,掛載前後,更新前後,銷燬前後,created階段Vue物件上掛載了methods和data,所以一般用來請求資料,mounted的時候檢視就渲染完了,一般可以操作DOM,比如Echarts初始化,這兩個平時用的最多,如果有記憶體洩漏或者要效能優化的話,可以考慮銷燬前將事件進行解綁,不過一般不寫也沒什麼影響,有keep-alive的話就多兩個週期,啟用前後(actived\deactived),這兩個後期用不用就要看需求了,還有個捕獲元件錯誤用的(errorCaptured),這個平時不怎麼用。
4.v-model的原理
v-model其實就是一個語法糖,原理是用v-bind繫結value,然後用oninput監聽把值再更新給繫結value的值,有時候封裝元件也可以用這個方法實現即使元件不是輸入框也可以進行v-model繫結資料。
v-model 在內部為不同的輸入元素使用不同的屬性並丟擲不同的事件:
- text 和 textarea 元素使用 value 屬性和 input 事件;
- checkbox 和 radio 使用 checked 屬性和 change 事件;
- select 欄位將 value 作為 prop 並將 change 作為事件。
<input v-model='something'> 等價於 <input v-bind:value="something" @input="something = $event.target.value">
如果在自定義元件中,v-model 預設會利用名為value 的 prop 和名為input的事件,如下所示:
父元件: <ModelChild v-model="message"></ModelChild> 子元件: <div>{{value}}</div> props:{ value: String }, methods: { test1(){ this.$emit('input', '小紅') }, },
5.v-if和v-show的區別
兩者都是控制標籤的隱藏或者出現(不含v-else)
兩者的區別:
- 控制手段不同
- 編譯過程不同
- 編譯條件不同
- 控制手段:v-if顯示隱藏是從DOM樹上建立或移除。v-show隱藏則是為該元素新增css樣式display:none。
- 編譯過程:v-if切換有一個區域性編譯/解除安裝的過程,切換過程中合適地銷燬和重建內部的事件監聽和子元件;v-show只是簡單的基於css切換
- 編譯條件:v-if是真正的條件渲染,它會確保在切換過程中條件塊內的事件監聽器和子元件適當地被銷燬和重建。只有渲染條件為false時,並不做操作,直到為true才渲染
v-show 由false變為true的時候不會觸發元件的生命週期
v-if由false變為true的時候,觸發元件的beforeCreate、created、beforeMount、mounted鉤子函式,由true變為false的時候觸發元件的beforeDestroy、destroyed鉤子函式
效能消耗:v-if有更高的切換消耗;v-show有更高的初始渲染消耗。
使用場景:
v-if
與v-show
都能控制dom
元素在頁面的顯示v-if
相比v-show
開銷更大的(直接操作dom
節點增刪)- 如果需要非常頻繁地切換,則使用 v-show 較好
- 如果在執行時條件很少改變,則使用 v-if 較好
6.說說你對SPA單頁面的理解,分別有什麼優缺點?
SPA(single-page application)僅在Web頁面初始化時載入相應的HTML、JavaScript和css,一旦頁面載入完成,SPA不會因為使用者的操作而進行頁面的重新載入或跳轉;取而代之的是利用路由機制實現HTML內容的變換,UI與使用者的互動,避免頁面的重新載入。
優點:
- 使用者體驗好,內容的改變不需要重新載入整個頁面,避免了不必要的跳轉和重複渲染;
- 基於上面一點,SPA對伺服器壓力小;
- 前後端職責分離,架構清晰,前端進行互動邏輯,後端負責資料處理;
- 初次載入耗時多:為實現單頁 Web 應用功能及顯示效果,需要在載入頁面的時候將 JavaScript、CSS 統一載入,部分頁面按需載入;
- 前進後退路由管理:由於單頁應用在一個頁面中顯示所有的內容,所以不能使用瀏覽器的前進後退功能,所有的頁面切換需要自己建立堆疊管理;
- SEO 難度較大:由於所有的內容都在一個頁面中動態替換顯示,所以在 SEO 上其有著天然的弱勢。
7.Vue元件間通訊有哪幾種方式?
Vue 元件間通訊是面試常考的知識點之一,這題有點類似於開放題,你回答出越多方法當然越加分,表明你對 Vue 掌握的越熟練。Vue 元件間通訊主要指以下 3 類通訊:父子元件通訊、隔代元件通訊、兄弟元件通訊,下面我們分別介紹每種通訊方式且會說明此種方法可適用於哪類元件間通訊。(1)props / $emit
適用 父子元件通訊
這種方法是 Vue 元件的基礎,相信大部分同學耳聞能詳,所以此處就不舉例展開介紹。
(2)ref
與$parent / $children
適用 父子元件通訊
ref
:如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子元件上,引用就指向元件例項$parent
/$children
:訪問父 / 子例項
(3)EventBus ($emit / $on)
適用於 父子、隔代、兄弟元件通訊
這種方法通過一個空的 Vue 例項作為中央事件匯流排(事件中心),用它來觸發事件和監聽事件,從而實現任何元件間的通訊,包括父子、隔代、兄弟元件。
(4)$attrs
/$listeners
適用於 隔代元件通訊
$attrs
:包含了父作用域中不被 prop 所識別 (且獲取) 的特性繫結 ( class 和 style 除外 )。當一個元件沒有宣告任何 prop 時,這裡會包含所有父作用域的繫結 ( class 和 style 除外 ),並且可以通過v-bind="$attrs"
傳入內部元件。通常配合 inheritAttrs 選項一起使用。$listeners
:包含了父作用域中的 (不含 .native 修飾器的) v-on 事件監聽器。它可以通過v-on="$listeners"
傳入內部元件
(5)provide / inject
適用於 隔代元件通訊
祖先元件中通過 provider 來提供變數,然後在子孫元件中通過 inject 來注入變數。 provide / inject API 主要解決了跨級元件間的通訊問題,不過它的使用場景,主要是子元件獲取上級元件的狀態,跨級元件間建立了一種主動提供與依賴注入的關係。
(6)Vuex 適用於 父子、隔代、兄弟元件通訊
Vuex 是一個專為 Vue.js 應用程式開發的狀態管理模式。每一個 Vuex 應用的核心就是 store(倉庫)。“store” 基本上就是一個容器,它包含著你的應用中大部分的狀態 ( state )。
- Vuex 的狀態儲存是響應式的。當 Vue 元件從 store 中讀取狀態的時候,若 store 中的狀態發生變化,那麼相應的元件也會相應地得到高效更新。
- 改變 store 中的狀態的唯一途徑就是顯式地提交 (commit) mutation。這樣使得我們可以方便地跟蹤每一個狀態的變化。
8.你使用過Vuex嗎?
Vuex是一個專為Vue.js應用程式開發的一個狀態管理工具,每個Vuex應用的核心就是store(倉庫),“store” 基本上就是一個容器,它包含著你的應用中大部分的狀態 ( state )。
(1) Vuex 的狀態儲存是響應式的。當 Vue 元件從 store 中讀取狀態的時候,若 store 中的狀態發生變化,那麼相應的元件也會相應地得到高效更新。
(2) 改變 store 中的狀態的唯一途徑就是顯式地提交 (commit) mutation。這樣使得我們可以方便地跟蹤每一個狀態的變化。
主要包括以下幾個模組:
- State:定義了應用狀態的資料結構,可以在這裡設定預設的初始狀態。
- Getter:允許元件從 Store 中獲取資料,mapGetters 輔助函式僅僅是將 store 中的 getter 對映到區域性計算屬性。
- Mutation:是唯一更改 store 中狀態的方法,且必須是同步函式。
- Action:用於提交 mutation,而不是直接變更狀態,可以包含任意非同步操作。
- Module:允許將單一的 Store 拆分為多個 store 且同時儲存在單一的狀態樹中。
(dispatch)Actions --> (commit)Mutations --> State --> Render Page(渲染頁面)
9.你知道DOM diff演算法嗎?
diff演算法是一種通過同層的樹節點進行比較的高效演算法。
兩個特點:
- 比較只會在同級進行,不會跨層級比較
- 在diff比較的過程中,迴圈從兩邊向中間比較
while
迴圈主要處理了以下五種情景:- 當新老
VNode
節點的start
相同時,直接patchVnode
,同時新老VNode
節點的開始索引都加 1 - 當新老
VNode
節點的end
相同時,同樣直接patchVnode
,同時新老VNode
節點的結束索引都減 1 - 當老
VNode
節點的start
和新VNode
節點的end
相同時,這時候在patchVnode
後,還需要將當前真實dom
節點移動到oldEndVnode
的後面,同時老VNode
節點開始索引加 1,新VNode
節點的結束索引減 1 - 當老
VNode
節點的end
和新VNode
節點的start
相同時,這時候在patchVnode
後,還需要將當前真實dom
節點移動到oldStartVnode
的前面,同時老VNode
節點結束索引減 1,新VNode
節點的開始索引加 1 - 如果都不滿足以上四種情形,那說明沒有相同的節點可以複用,則會分為以下兩種情況:
- 從舊的
VNode
為key
值,對應index
序列為value
值的雜湊表中找到與newStartVnode
一致key
的舊的VNode
節點,再進行patchVnode
,同時將這個真實dom
移動到oldStartVnode
對應的真實dom
的前面 - 呼叫
createElm
建立一個新的dom
節點放到當前newStartIdx
的位置
- 從舊的
10.$nextTick是什麼?
官方對其的定義:
在下次DOM更新迴圈結束之後執行延遲迴調。在修改資料之後立即使用這個方法,獲取更新後的DOM
可以這樣通俗的理解:
在vue中修改資料會進行虛擬DOM的更新,這是個同步操作,而虛擬DOM更新後同步到真實的DOM節點更新的過程是一個非同步操作,所以沒法再更新完資料同步的獲取DOM的最新狀態,$nextTick就是一個非同步包裝,可以將包裝起來的操作變成非同步的,和setTimeout差不多,比如:一個div的文字是data中的資料,你修改了以後立刻獲取div的內容,其實是獲取不到的,因為非同步更新還沒執行,所以要想操作就得將操作包裝成非同步,可以使用$nextTick,或者在updated週期處理。