Vue最全知識點
宣告:本篇文章純屬筆記性文章,非整體原創,是對vue知識的整理,
基礎篇
說說你對MVVM的理解
- Model-View-ViewModel的縮寫,Model代表資料模型,View代表UI元件,ViewModel將Model和View關聯起來
- 資料會繫結到viewModel層並自動將資料渲染到頁面中,檢視變化的時候會通知viewModel層更新資料
瞭解mvc/mvp/mvvm的區別
Vue2.x響應式資料/雙向繫結原理
-
Vue 資料雙向繫結主要是指:資料變化更新檢視,檢視變化更新資料。其中,View變化更新Data,可以通過事件監聽的方式來實現,所以 Vue資料雙向繫結的工作主要是如何根據Data變化更新View
-
簡述:
- 當你把一個普通的 JavaScript 物件傳入 Vue 例項作為 data 選項,Vue 將遍歷此物件所有的 property,並使用 Object.defineProperty 把這些 property 全部轉為 getter/setter。
- 這些 getter/setter 對使用者來說是不可見的,但是在內部它們讓 Vue 能夠追蹤依賴,在 property 被訪問和修改時通知變更。
- 每個元件例項都對應一個 watcher 例項,它會在元件渲染的過程中把“接觸”過的資料 property 記錄為依賴。之後當依賴項的 setter 觸發時,會通知 watcher,從而使它關聯的元件重新渲染。
-
深入理解:
- 監聽器 Observer:對資料物件進行遍歷,包括子屬性物件的屬性,利用 Object.defineProperty() 對屬性都加上 setter 和 getter。這樣的話,給這個物件的某個值賦值,就會觸發 setter,那麼就能監聽到了資料變化。
- 解析器 Compile:解析 Vue 模板指令,將模板中的變數都替換成資料,然後初始化渲染頁面檢視,並將每個指令對應的節點繫結更新函式,新增監聽資料的訂閱者,一旦資料有變動,收到通知,呼叫更新函式進行資料更新。
- 訂閱者 Watcher:Watcher 訂閱者是 Observer 和 Compile 之間通訊的橋樑 ,主要的任務是訂閱 Observer 中的屬性值變化的訊息,當收到屬性值變化的訊息時,觸發解析器 Compile 中對應的更新函式。每個元件例項都有相應的 watcher 例項物件,它會在元件渲染的過程中把屬性記錄為依賴,之後當依賴項的 setter 被呼叫時,會通知 watcher 重新計算,從而致使它關聯的元件得以更新——這是一個典型的觀察者模式
- 訂閱器 Dep:訂閱器採用 釋出-訂閱 設計模式,用來收集訂閱者 Watcher,對監聽器 Observer 和 訂閱者 Watcher 進行統一管理。
你知道Vue3.x響應式資料原理嗎?
-
Vue3.x改用Proxy替代Object.defineProperty。
-
因為Proxy可以直接監聽物件和陣列的變化,並且有多達13種攔截方法。並且作為新標準將受到瀏覽器廠商重點持續的效能優化。
-
Proxy只會代理物件的第一層,Vue3是怎樣處理這個問題的呢?
- 判斷當前Reflect.get的返回值是否為Object,如果是則再通過reactive方法做代理, 這樣就實現了深度觀測。
- 監測陣列的時候可能觸發多次get/set,那麼如何防止觸發多次呢?我們可以判斷key是否為當前被代理物件target自身屬性,也可以判斷舊值與新值是否相等,只有滿足以上兩個條件之一時,才有可能執行trigger。
Proxy 與 Object.defineProperty 優劣對比
-
Proxy 的優勢如下:
- Proxy 可以直接監聽物件而非屬性;
-
Proxy 可以直接監聽陣列的變化;
- Proxy 有多達 13 種攔截方法,不限於 apply、ownKeys、deleteProperty、has 等等是 Object.defineProperty 不具備的;
- Proxy 返回的是一個新物件,我們可以只操作新的物件達到目的,而 Object.defineProperty 只能遍歷物件屬性直接修改;
- Proxy 作為新標準將受到瀏覽器廠商重點持續的效能優化,也就是傳說中的新標準的效能紅利;
-
Object.defineProperty 的優勢如下:
- 相容性好,支援 IE9,而 Proxy 的存在瀏覽器相容性問題,而且無法用 polyfill 磨平,因此 Vue 的作者才宣告需要等到下個大版本( 3.0 )才能用 Proxy 重寫。
VUEX篇
Vuex 是什麼?
運用到了js設計模式中的單例模式,單例模式想要做到的是,不管我們嘗試去建立多少次,它都只給你返回第一次所建立的那唯一的一個例項。
-
Vuex 是一個專為 Vue.js 應用程式開發的狀態管理模式。每一個 Vuex 應用的核心就是 store(倉庫)。“store” 基本上就是一個容器,它包含著你的應用中大部分的狀態 ( state )。
- Vuex 的狀態儲存是響應式的。當 Vue 元件從 store 中讀取狀態的時候,若 store 中的狀態發生變化,那麼相應的元件也會相應地得到高效更新。
- 改變 store 中的狀態的唯一途徑就是顯式地提交 (commit) mutation。這樣使得我們可以方便地跟蹤每一個狀態的變化。
Vuex 使用單一狀態樹,用一個物件就包含了全部的應用層級狀態。至此它便作為一個“唯一資料來源 (SSOT)”而存在。這也意味著,每個應用將僅僅包含一個 store 例項。單一狀態樹讓我們能夠直接地定位任一特定的狀態片段,在除錯的過程中也能輕易地取得整個當前應用狀態的快照。——Vuex官方文件
-
主要包括以下幾個模組:
- State:定義了應用狀態的資料結構,可以在這裡設定預設的初始狀態。
- Getter:允許元件從 Store 中獲取資料,mapGetters 輔助函式僅僅是將 store 中的 getter 對映到區域性計算屬性。
- Mutation:是唯一更改 store 中狀態的方法,且必須是同步函式。
- Action:用於提交 mutation,而不是直接變更狀態,可以包含任意非同步操作。
- Module:允許將單一的 Store 拆分為多個 store 且同時儲存在單一的狀態樹中。
什麼情況下使用 Vuex?
- 如果應用夠簡單,最好不要使用 Vuex,一個簡單的 store 模式即可
- 需要構建一箇中大型單頁應用時,使用Vuex能更好地在元件外部管理狀態
Vuex和單純的全域性物件有什麼區別?
- Vuex 的狀態儲存是響應式的。當 Vue 元件從 store 中讀取狀態的時候,若 store 中的狀態發生變化,那麼相應的元件也會相應地得到高效更新。
- 不能直接改變 store 中的狀態。改變 store 中的狀態的唯一途徑就是顯式地提交 (commit) mutation。這樣使得我們可以方便地跟蹤每一個狀態的變化,從而讓我們能夠實現一些工具幫助我們更好地瞭解我們的應用。
為什麼 Vuex 的 mutation 中不能做非同步操作?
- Vuex中所有的狀態更新的唯一途徑都是mutation,非同步操作通過 Action 來提交 mutation實現,這樣使得我們可以方便地跟蹤每一個狀態的變化,從而讓我們能夠實現一些工具幫助我們更好地瞭解我們的應用。
- 每個mutation執行完成後都會對應到一個新的狀態變更,這樣devtools就可以打個快照存下來,然後就可以實現 time-travel 了。如果mutation支援非同步操作,就沒有辦法知道狀態是何時更新的,無法很好的進行狀態的追蹤,給除錯帶來困難。
新增:vuex的action有返回值嗎?返回的是什麼?
- store.dispatch 可以處理被觸發的 action 的處理函式返回的 Promise,並且 store.dispatch 仍舊返回 Promise
- Action 通常是非同步的,要知道 action 什麼時候結束或者組合多個 action以處理更加複雜的非同步流程,可以通過定義action時返回一個promise物件,就可以在派發action的時候就可以通過處理返回的 Promise處理非同步流程
一個 store.dispatch 在不同模組中可以觸發多個 action 函式。在這種情況下,只有當所有觸發函式完成後,返回的 Promise 才會執行。
新增:為什麼不直接分發mutation,而要通過分發action之後提交 mutation變更狀態
- mutation 必須同步執行,我們可以在 action 內部執行非同步操作
- 可以進行一系列的非同步操作,並且通過提交 mutation 來記錄 action 產生的副作用(即狀態變更)
常規篇
computed 和 watch 的區別和運用的場景?
-
computed:是計算屬性,依賴其它屬性值,並且 computed 的值有快取,只有它依賴的屬性值發生改變,下一次獲取 computed 的值時才會重新計算 computed 的值;
-
watch:沒有快取性,更多的是「觀察」的作用,類似於某些資料的監聽回撥 ,每當監聽的資料變化時都會執行回撥進行後續操作;當我們需要深度監聽物件中的屬性時,可以開啟deep:true選項,這樣便會對物件中的每一項進行監聽
-
運用場景:
- 當我們需要進行數值計算,並且依賴於其它資料時,應該使用 computed,因為可以利用 computed 的快取特性,避免每次獲取值時,都要重新計算;
- 當我們需要在資料變化時執行非同步或開銷較大的操作時,應該使用 watch,使用watch選項允許我們執行非同步操作 ( 訪問一個 API ),限制我們執行該操作的頻率,並在我們得到最終結果前,設定中間狀態。這些都是計算屬性無法做到的。
Vue2.x元件通訊有哪些方式?
-
父子元件通訊
- 事件機制(**父->子props,子->父
$on、$emit
) - 獲取父子元件例項
$parent、$children
- Ref 獲取例項的方式呼叫元件的屬性或者方法
- Provide、inject (不推薦使用,元件庫時很常用)
-
兄弟元件通訊
Vue.prototype.
$bus
= new Vue - Vuex
- eventBus這種方法通過一個空的 Vue例項作為中央事件匯流排(事件中心),用它來觸發事件和監聽事件,從而實現任何元件間的通訊,包括父子、隔代、兄弟元件
-
跨級元件通訊
- Vuex
$attrs、$listeners
- Provide、inject
說一下v-if和v-show的區別
- 當條件不成立時,v-if不會渲染DOM元素,v-show操作的是樣式(display),切換當前DOM的顯示和隱藏。
- v-if 適用於在執行時很少改變條件,不需要頻繁切換條件的場景;
- v-show 則適用於需要非常頻繁切換條件的場景。
為什麼 v-for 和 v-if 不建議用在一起
- 當 v-for 和 v-if 處於同一個節點時,v-for 的優先順序比 v-if 更高,這意味著 v-if 將分別重複運行於每個 v-for 迴圈中。如果要遍歷的陣列很大,而真正要展示的資料很少時,這將造成很大的效能浪費
- 這種場景建議使用 computed,先對資料進行過濾
元件中的data為什麼是一個函式?
- 一個元件被複用多次的話,也就會建立多個例項。本質上,這些例項用的都是同一個建構函式。
- 如果data是物件的話,物件屬於引用型別,會影響到所有的例項。所以為了保證元件不同的例項之間data不衝突,data必須是一個函式。
子元件為什麼不可以修改父元件傳遞的Prop?/怎麼理解vue的單向資料流?
- Vue提倡單向資料流,即父級props的更新會流向子元件,但是反過來則不行。
- 這是為了防止意外的改變父元件狀態,使得應用的資料流變得難以理解。
- 如果破壞了單向資料流,當應用複雜時,debug 的成本會非常高。
v-model是如何實現雙向繫結的?
- v-model是用來在表單控制元件或者元件上建立雙向繫結的
- 他的本質是v-bind和v-on的語法糖
- 在一個元件上使用v-model,預設會為元件繫結名為value的prop和名為input的事件
nextTick的實現原理是什麼?
- 在下次 DOM 更新迴圈結束之後執行延遲迴調,在修改資料之後立即使用 nextTick 來獲取更新後的 DOM。
- nextTick主要使用了巨集任務和微任務。
- 根據執行環境分別嘗試採用Promise、MutationObserver、setImmediate,如果以上都不行則採用setTimeout定義了一個非同步方法,多次呼叫nextTick會將方法存入佇列中,通過這個非同步方法清空當前佇列。
Vue不能檢測陣列的哪些變動?Vue 怎麼用vm.$set()
解決物件新增屬性不能響應的問題 ?
-
Vue 不能檢測以下陣列的變動:
-
第一類問題
// 法一:Vue.set Vue.set(vm.items, indexOfItem, newValue) // 法二:Array.prototype.splice vm.items.splice(indexOfItem, 1, newValue) 複製程式碼
-
第二類問題,可使用 splice:
vm.items.splice(newLength) 複製程式碼
-
當你利用索引直接設定一個數組項時,例如:vm.items[indexOfItem] = newValue
-
當你修改陣列的長度時,例如:vm.items.length = newLength
-
解決辦法:
-
vm.
$set
的實現原理是: - 如果目標是陣列,直接使用陣列的 splice 方法觸發相應式;
- 如果目標是物件,會先判讀屬性是否存在、物件是否是響應式,最終如果要對屬性進行響應式處理,則是通過呼叫 defineReactive 方法進行響應式處理( defineReactive 方法就是 Vue 在初始化物件時,給物件屬性採用 Object.defineProperty 動態新增 getter 和 setter 的功能所呼叫的方法)
Vue事件繫結原理是什麼?
- 原生事件繫結是通過addEventListener繫結給真實元素的,元件事件繫結是通過Vue自定義的
$on
實現的。
說一下虛擬Dom以及key屬性的作用
-
由於在瀏覽器中操作DOM是很昂貴的。頻繁的操作DOM,會產生一定的效能問題。這就是虛擬Dom的產生原因。
-
Virtual DOM本質就是用一個原生的JS物件去描述一個DOM節點。是對真實DOM的一層抽象。(也就是原始碼中的VNode類,它定義在src/core/vdom/vnode.js中。)
-
虛擬 DOM 的實現原理主要包括以下 3 部分:
- 用 JavaScript 物件模擬真實 DOM 樹,對真實 DOM 進行抽象;
- diff 演算法 — 比較兩棵虛擬 DOM 樹的差異;
- pach 演算法 — 將兩個虛擬 DOM 物件的差異應用到真正的 DOM 樹。
-
key 是為 Vue 中 vnode 的唯一標記,通過這個 key,我們的 diff 操作可以更準確、更快速
- 更準確:因為帶 key 就不是就地複用了,在 sameNode 函式a.key === b.key對比中可以避免就地複用的情況。所以會更加準確。
- 更快速:利用 key 的唯一性生成 map 物件來獲取對應節點,比遍歷方式更快
為什麼不建議用index作為key?
- 不建議 用index 作為 key,和沒寫基本上沒區別,因為不管你陣列的順序怎麼顛倒,index 都是 0, 1, 2 這樣排列,導致 Vue 會複用錯誤的舊子節點,做很多額外的工作
生命週期篇
說一下你對Vue的生命週期的理解
-
簡單回答
- beforeCreate、created、beforeMount、mounted、beforeUpdate、updated、beforeDestroy、destroyed。
- keep-alive 有自己獨立的鉤子函式 activated 和 deactivated。
-
複雜回答
| 生命週期
發生了什麼 |
---|
beforeCreate |
created |
beforeMount |
mounted |
beforeUpdate |
updated |
beforeDestroy |
destroyed |
activited keep-alive 專屬 |
deactivated keep-alive 專屬 |
Vue中元件生命週期呼叫順序是什麼樣的?
- 元件的呼叫順序都是先父後子,渲染完成的順序是先子後父。
- 元件的銷燬操作是先父後子,銷燬完成的順序是先子後父。
在什麼階段才能訪問操作DOM?
在鉤子函式 mounted 被呼叫前,Vue 已經將編譯好的模板掛載到頁面上,所以在 mounted 中可以訪問操作 DOM。
你的介面請求一般放在哪個生命週期中?
-
可以在鉤子函式 created、beforeMount、mounted 中進行呼叫,因為在這三個鉤子函式中,data 已經建立,可以將服務端端返回的資料進行賦值。
-
但是推薦在 created 鉤子函式中呼叫非同步請求,因為在 created 鉤子函式中呼叫非同步請求有以下優點:
- 能更快獲取到服務端資料,減少頁面loading 時間;
- ssr不支援 beforeMount 、mounted 鉤子函式,所以放在 created 中有助於一致性;
路由篇
vue路由hash模式和history模式實現原理分別是什麼,他們的區別是什麼?
-
hash 模式:
- #後面 hash 值的變化,不會導致瀏覽器向伺服器發出請求,瀏覽器不發出請求,就不會重新整理頁面
- 通過監聽hashchange事件可以知道 hash 發生了哪些變化,然後根據 hash 變化來實現更新頁面部分內容的操作。
-
history 模式:
- history 模式的實現,主要是 HTML5 標準釋出的兩個 API,pushState和replaceState,這兩個 API 可以在改變 url,但是不會發送請求。這樣就可以監聽 url 變化來實現更新頁面部分內容的操作
-
區別
- url 展示上,hash 模式有“#”,history 模式沒有
- 重新整理頁面時,hash 模式可以正常載入到 hash 值對應的頁面,而 history 沒有處理的話,會返回 404,一般需要後端將所有頁面都配置重定向到首頁路由
- 相容性,hash 可以支援低版本瀏覽器和 IE。
路由懶載入是什麼意思?如何實現路由懶載入?
-
路由懶載入的含義:把不同路由對應的元件分割成不同的程式碼塊,然後當路由被訪問的時候才載入對應元件
-
實現:結合 Vue 的非同步元件和 Webpack 的程式碼分割功能
-
1. 可以將非同步元件定義為返回一個 Promise 的工廠函式 \(該函式返回的 Promise 應該 resolve 元件本身\)
const Foo = () => Promise.resolve({ /* 元件定義物件 */ }) 複製程式碼
-
2. 在 Webpack 2 中,我們可以使用動態 import語法來定義程式碼分塊點 \(split point\)
import('./Foo.vue') // 返回 Promise 複製程式碼
-
結合這兩者,這就是如何定義一個能夠被 Webpack 自動程式碼分割的非同步元件
const Foo = () => import('./Foo.vue') const router = new VueRouter({ routes: [ { path: '/foo', component: Foo } ]}) 複製程式碼
-
使用命名 chunk,和webpack中的魔法註釋就可以把某個路由下的所有元件都打包在同個非同步塊 (chunk) 中
chunkconst Foo = () => import(/* webpackChunkName: "group-foo" */ './Foo.vue') 複製程式碼
Vue-router 導航守衛有哪些
- 全域性前置/鉤子:beforeEach、beforeResolve、afterEach
- 路由獨享的守衛:beforeEnter
- 元件內的守衛:beforeRouteEnter、beforeRouteUpdate、beforeRouteLeave
進階篇
說說vue和react的異同
-
同
- 使用 Virtual DOM
- 提供了響應式 (Reactive) 和元件化 (Composable) 的檢視元件。
- 將注意力集中保持在核心庫,而將其他功能如路由和全域性狀態管理交給相關的庫。
-
異
- 在 React 應用中,當某個元件的狀態發生變化時,它會以該元件為根,重新渲染整個元件子樹(除非使用PureComponent/shouldComponentUpdate),在 Vue 應用中,元件的依賴是在渲染過程中自動追蹤的,所以系統能精確知曉哪個元件確實需要被重渲染
- 在 React 中,一切都是 JavaScript。不僅僅是 HTML 可以用 JSX 來表達,現在的潮流也越來越多地將 CSS 也納入到 JavaScript 中來處理
- Vue 的路由庫和狀態管理庫都是由官方維護支援且與核心庫同步更新的。React 則是選擇把這些問題交給社群維護,因此建立了一個更分散的生態系統,所以有更豐富的生態系統
- Vue 提供了CLI 腳手架,能讓你通過互動式的腳手架引導非常容易地構建專案。你甚至可以使用它快速開發元件的原型。React 在這方面也提供了create-react-app,但是現在還存在一些侷限性
- React Native 能使你用相同的元件模型編寫有本地渲染能力的 APP,Vue 和Weex會進行官方合作,Weex 是阿里巴巴發起的跨平臺使用者介面開發框架,同時也正在 Apache 基金會進行專案孵化,另一個選擇是NativeScript-Vue,一個用 Vue.js 構建完全原生應用的NativeScript外掛
什麼是 mixin ?
- Mixin 使我們能夠為 Vue 元件編寫可插拔和可重用的功能。
- 如果你希望再多個元件之間重用一組元件選項,例如生命週期 hook、 方法等,則可以將其編寫為 mixin,並在元件中簡單的引用它。
- 然後將 mixin 的內容合併到元件中。如果你要在 mixin 中定義生命週期 hook,那麼它在執行時將優化於元件自已的 hook。
在 Vue 例項中編寫生命週期 hook 或其他 option/properties 時,為什麼不使用箭頭函式 ?
- 箭頭函式自已沒有定義 this 上下文中。
- 當你在 Vue 程式中使用箭頭函式 ( => ) 時,this 關鍵字病不會繫結到 Vue 例項,因此會引發錯誤。所以強烈建議改用標準函式宣告。
Vue模版編譯原理知道嗎,能簡單說一下嗎?
簡單說,Vue的編譯過程就是將template轉化為render函式的過程。會經歷以下階段(生成AST樹/優化/codegen):
- 首先解析模版,生成AST語法樹(一種用JavaScript物件的形式來描述整個模板)。使用大量的正則表示式對模板進行解析,遇到標籤、文字的時候都會執行對應的鉤子進行相關處理。
- Vue的資料是響應式的,但其實模板中並不是所有的資料都是響應式的。有一些資料首次渲染後就不會再變化,對應的DOM也不會變化。那麼優化過程就是深度遍歷AST樹,按照相關條件對樹節點進行標記。這些被標記的節點(靜態節點)我們就可以跳過對它們的比對,對執行時的模板起到很大的優化作用。
- 編譯的最後一步是將優化後的AST樹轉換為可執行的程式碼。
diff演算法說一下
- 同級比較,再比較子節點
- 先判斷一方有子節點一方沒有子節點的情況(如果新的children沒有子節點,將舊的子節點移除)
- 比較都有子節點的情況(核心diff)
- 遞迴比較子節點
說說你對keep-alive元件的瞭解
-
keep-alive 是 Vue 內建的一個元件,可以使被包含的元件保留狀態,避免重新渲染 ,其有以下特性:
- 一般結合路由和動態元件一起使用,用於快取元件;
- 提供 include 和 exclude 屬性,兩者都支援字串或正則表示式, include 表示只有名稱匹配的元件會被快取,exclude 表示任何名稱匹配的元件都不會被快取 ,其中 exclude 的優先順序比 include 高;
- 對應兩個鉤子函式 activated 和 deactivated ,當元件被啟用時,觸發鉤子函式 activated,當元件被移除時,觸發鉤子函式 deactivated。
說說你對SSR的瞭解
-
SSR也就是服務端渲染,也就是將Vue在客戶端把標籤渲染成HTML的工作放在服務端完成,然後再把html直接返回給客戶端
-
SSR的優勢
- 更好的SEO
- 首屏載入速度更快
-
SSR的缺點
- 開發條件會受到限制,伺服器端渲染只支援beforeCreate和created兩個鉤子
- 當我們需要一些外部擴充套件庫時需要特殊處理,服務端渲染應用程式也需要處於Node.js的執行環境
- 更多的服務端負載
你都做過哪些Vue的效能優化?
-
編碼階段
- 儘量減少data中的資料,data中的資料都會增加getter和setter,會收集對應的watcher
- v-if和v-for不能連用
- 如果需要使用v-for給每項元素繫結事件時使用事件代理
- SPA 頁面採用keep-alive快取元件
- 在更多的情況下,使用v-if替代v-show
- key保證唯一
- 使用路由懶載入、非同步元件
- 防抖、節流
- 第三方模組按需匯入
- 長列表滾動到可視區域動態載入
- 圖片懶載入
-
SEO優化
- 預渲染
- 服務端渲染SSR
-
打包優化
- 壓縮程式碼
- Tree Shaking/Scope Hoisting
- 使用cdn載入第三方模組
- 多執行緒打包happypack
- splitChunks抽離公共檔案
- sourceMap優化
-
使用者體驗
- 骨架屏
- PWA
- 還可以使用快取(客戶端快取、服務端快取)優化、服務端開啟gzip壓縮等。
vue2.x中如何監測陣列變化?
- 使用了函式劫持的方式,重寫了陣列的方法,Vue將data中的陣列進行了原型鏈重寫,指向了自己定義的陣列原型方法,當呼叫陣列api時,可以通知依賴更新。
- 如果陣列中包含著引用型別,會對陣列中的引用型別再次遞迴遍歷進行監控。這樣就實現了監測陣列變化。
說說你對 SPA 單頁面的理解,它的優缺點分別是什麼?
-
SPA( single-page application )僅在 Web 頁面初始化時載入相應的 HTML、JavaScript 和 CSS。一旦頁面載入完成,SPA 不會因為使用者的操作而進行頁面的重新載入或跳轉;取而代之的是利用路由機制實現 HTML 內容的變換,UI 與使用者的互動,避免頁面的重新載入。
-
優點:
- 使用者體驗好、快,內容的改變不需要重新載入整個頁面,避免了不必要的跳轉和重複渲染;
- 基於上面一點,SPA 相對對伺服器壓力小;
- 前後端職責分離,架構清晰,前端進行互動邏輯,後端負責資料處理;
-
缺點:
- 初次載入耗時多:為實現單頁 Web 應用功能及顯示效果,需要在載入頁面的時候將 JavaScript、CSS 統一載入,部分頁面按需載入;
- 前進後退路由管理:由於單頁應用在一個頁面中顯示所有的內容,所以不能使用瀏覽器的前進後退功能,所有的頁面切換需要自己建立堆疊管理;
- SEO 難度較大:由於所有的內容都在一個頁面中動態替換顯示,所以在 SEO 上其有著天然的弱勢。
對於即將到來的 vue3.0 特性你有什麼瞭解的嗎?
-
監測機制的改變
- 3.0 將帶來基於代理 Proxy的 observer 實現,提供全語言覆蓋的反應性跟蹤。
- 消除了 Vue 2 當中基於 Object.defineProperty 的實現所存在的很多限制:
-
只能監測屬性,不能監測物件
- 檢測屬性的新增和刪除;
- 檢測陣列索引和長度的變更;
- 支援 Map、Set、WeakMap 和 WeakSet。
-
模板
- 模板方面沒有大的變更,只改了作用域插槽,2.x 的機制導致作用域插槽變了,父元件會重新渲染,而 3.0 把作用域插槽改成了函式的方式,這樣只會影響子元件的重新渲染,提升了渲染的效能。
- 同時,對於 render 函式的方面,vue3.0 也會進行一系列更改來方便習慣直接使用 api 來生成 vdom 。
-
物件式的元件宣告方式
- vue2.x 中的元件是通過宣告的方式傳入一系列 option,和 TypeScript 的結合需要通過一些裝飾器的方式來做,雖然能實現功能,但是比較麻煩。
- 3.0 修改了元件的宣告方式,改成了類式的寫法,這樣使得和 TypeScript 的結合變得很容易
-
其它方面的更改
- 支援自定義渲染器,從而使得 weex 可以通過自定義渲染器的方式來擴充套件,而不是直接 fork 原始碼來改的方式。
- 支援 Fragment(多個根節點)和 Protal(在 dom 其他部分渲染組建內容)元件,針對一些特殊的場景做了處理。
- 基於 tree shaking 優化,提供了更多的內建功能。