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組件間通信有哪幾種方式?
(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周期處理。