vue作者尤雨溪在開發 vue3.0 的時候開發的一個基于浏覽器原生 ES imports 的開發伺服器(開發建構工具)。那麼我們先來了解一下vite
Vite,一個基于浏覽器原生 ES imports 的開發伺服器。利用浏覽器去解析 imports,在伺服器端按需編譯傳回,完全跳過了打包這個概念,伺服器随起随用。同時不僅有 Vue 檔案支援,還搞定了熱更新,而且熱更新的速度不會随着子產品增多而變慢。針對生産環境則可以把同一份代碼用 rollup 打。雖然現在還比較粗糙,但這個方向我覺得是有潛力的,做得好可以徹底解決改一行代碼等半天熱更新的問題。它做到了本地快速開發啟動, 用 vite 文檔上的介紹,它具有以下特點:
快速的冷啟動,不需要等待打包操作;
即時的熱子產品更新,替換性能和子產品數量的解耦讓更新飛起;
真正的按需編譯,不再等待整個應用編譯完成;
使用 npm:
或者 yarn:

速度更快
體積減少
更易維護
更接近原生
更易使用
重寫了虛拟Dom實作
diff算法優化
被編譯成:
首先靜态節點進行提升,會提升到 render 函數外面,這樣一來,這個靜态節點永遠隻被建立一次,之後直接在 render 函數中使用就行了。
Vue在運作時會生成number(大于0)值的PatchFlag,用作标記,僅帶有PatchFlag标記的節點會被真正追蹤,無論層級嵌套多深,它的動态節點都直接與Block根節點綁定,無需再去周遊靜态節點,是以處理的資料量減少,性能得到很大的提升。
事件監聽緩存:cacheHandlers
優化前:
onClick會被視為PROPS動态綁定,後續替換點選事件時需要進行更新。
優化後:
會自動生成一個内聯函數,這個内聯函數裡面再去引用目前元件最新的onclick,然後把這個内聯函數cache起來,第一次渲染的時候會建立内聯函數并且緩存,後續的更新就直接從緩存裡面讀同一個函數,既然是同一個函數就沒有再更新的必要,就變成了一個靜态節點
3. SSR速度提高
當有大量靜态的内容時,這些内容會被當做純字元串推進一個buffer裡面,即使存在動态的綁定,會通過模闆 插值嵌入進去,這樣會比通過虛拟dom來渲染的快很多。vue3.0 當靜态檔案大到一定量的時候,會用_ceratStaticVNode方法在用戶端去生成一個static node, 這些靜态node,會被直接innerHtml,就不需要建立對象,然後根據對象渲染
tree-shaking
tree-shakinng 原理 主要依賴es6的子產品化的文法,es6子產品依賴關系是确定的,和運作時的狀态無關,可以進行可靠的靜态分析, 分析程式流,判斷哪些變量未被使用、引用,進而删除對應代碼 前提是所有的東西都必須用ES6 module的import來寫
按照作者的原話解釋,Tree-shaking其實就是:把無用的子產品進行“剪枝”,很多沒有用到的API就不會打包到最後的包裡
在Vue2中,全局 API 如 Vue.nextTick() 是不支援 tree-shake 的,不管它們實際是否被使用,都會被包含在最終的打包産物中。
而Vue3源碼引入tree shaking特性,将全局 API 進行分塊。如果你不使用其某些功能,它們将不會包含在你的基礎包中
5. compositon Api
沒有Composition API之前vue相關業務的代碼需要配置到option的特定的區域,中小型項目是沒有問題的,但是在大型項目中會導緻後期的維護性比較複雜,同時代碼可複用性不高
compositon api提供了以下幾個函數:
setup (入口函數,接收兩個參數(props,context))
ref (将一個原始資料類型轉換成一個帶有響應式特性)
reactive (reactive 用來定義響應式的對象)
watchEffect
watch
computed
toRefs (解構響應式對象資料)
生命周期的hooks
如果用ref處理對象或數組,内部會自動将對象/數組轉換為reactive的代理對象
ref内部:通過給value屬性添加getter/setter來實作對資料的劫持
reactive内部:通過使用proxy來實作對對象内部所有資料的劫持,并通過Reflect反射操作對象内部資料
ref的資料操作:在js中使用ref對象.value擷取資料,在模闆中可直接使用
靈活的邏輯組合與複用
可與現有的Options API一起使用
與選項API最大的差別的是邏輯的關注點
選項API這種碎片化使得了解和維護複雜元件變得困難,在處理單個邏輯關注點時,我們必須不斷地上下翻找相關代碼的選項塊。
compositon API将同一個邏輯關注點相關代碼收集在一起
6. Fragment(碎片)
Vue 3不再限于模闆中的單個根節點,它正式支援了多根節點的元件,可純文字,多節點,v-for等
render 函數也可以傳回數組
7. Teleport(傳送門)
這個元件的作用主要用來将模闆内的 DOM 元素移動到其他位置。
允許我們控制在 DOM 中哪個父節點下渲染了 HTML
更好的Typescript支援
vue3是基于typescipt編寫的,可以享受到自動的類型定義提示
自定義渲染 API
vue官方實作的 createApp 會給我們的 template 映射生成 html 代碼,但是要是你不想渲染生成到 html ,而是要渲染生成到 canvas 之類的不是html的代碼的時候,那就需要用到 Custom Renderer API 來定義自己的 render 渲染生成函數了。
意味着以後可以通過 vue, Dom 程式設計的方式來進行canvas、webgl 程式設計
預設的目标渲染平台
自定義目标渲染平台
響應原理的變化
vue2對象響應化:周遊每個key,通過 Object.defineProperty API定義getter,setter 進而觸發一些視圖更新
數組響應化:覆寫數組的原型方法,增加通知變更的邏輯
vue2響應式痛點
遞歸,消耗大
新增/删除屬性,需要額外實作單獨的API
數組,需要額外實作
Map Set Class等資料類型,無法響應式
修改文法有限制
vue3響應式方案: 使用ES6的Proxy進行資料響應化,解決上述vue2所有痛點,Proxy可以在目标對象上加一層攔截/代理,外界對目标對象的操作,都會經過這層攔截。Proxy可以在目标對象上加一層攔截/代理,外界對目标對象的操作,都會經過這層攔截,相比 Object.defineProperty ,Proxy支援的對象操作十分全面
vue2使用全局api 如 Vue.component, Vue.mixin, Vue.use等,缺點是會導緻所建立的根執行個體将共享相同的全局配置(從相同的 Vue 構造函數建立的每個根執行個體都共享同一套全局環境。這樣就導緻一個問題,隻要某一個根執行個體對 全局 API 和 全局配置做了變動,就會影響由相同 Vue 構造函數建立的其他根執行個體。)
vue3 新增了createApp,調用createApp傳回一個應用執行個體,擁有全局API的一個子集,任何全局改變 Vue 行為的 API 現在都會移動到應用執行個體上
createApp初始化後會傳回一個app對象,裡面包含一個mount函數
mount函數是被重寫過的
處理傳入的容器并生成節點;
判斷傳入的元件是不是函數元件,元件裡有沒有render函數,template屬性,沒有就用容器的innerHTML作為元件的template;
清空容器内容
運作緩存的mount函數實作挂載元件;
元件上 v-model 用法更改,替換 v-bind.sync
vue2預設會利用名為 value 的 prop 和名為 input 的事件
如果想要更改 prop 或事件名稱,則需要在元件中添加 model 選項:
model選項,允許元件自定義用于 v-model 的 prop 和事件
使用 <code>title</code> 代替 <code>value</code> 作為 model 的 prop
vue2.3 新增.sync (對某一個 prop 進行“雙向綁定”,是update:title 事件的簡寫)
在 3.x 中,自定義元件上的 v-model 相當于傳遞了 modelValue prop 并接收抛出的 update:modelValue 事件
prop:value -> modelValue;
event:input -> update:modelValue
v-bind 的 .sync 修飾符群組件的 model 選項已移除,可用 v-model加參數 作為代替
vue3 可以将一個 argument 傳遞給 v-model:
<code><ChildComponent v-model:title="pageTitle" /></code>
等價于
<code><ChildComponent :title="pageTitle" @update:title="pageTitle = $event" /></code>
可使用多個model
可以在template元素上添加 key
同一節點v-if 比 v-for 優先級更高
v-bind="object" 現在排序敏感(綁定相同property,vue2單獨的 property 總是會覆寫 object 中的綁定。vue3按順序決定如何合并)
移除 v-on.native 修飾符
Vue 2 如果想要在一個元件的根元素上直接監聽一個原生事件,需要使用v-on 的 .native 修飾符
Vue3 現在将所有未在元件emits 選項中定義的事件作為原生事件添加到子元件的根元素中(除非子元件選項中設定了 inheritAttrs: false)。
(強烈建議元件中使用的所有通過emit觸發的event都在emits中聲明)
v-for 中的 ref 不再注冊 ref 數組
vue2在 v-for 語句中使用ref屬性時,會生成refs數組插入$refs屬性中。由于當存在嵌套的v-for時,這種處理方式會變得複雜且低效。
vue3在 v-for 語句中使用ref屬性 将不再會自動在$refs中建立數組。而是,将 ref 綁定到一個 function 中,在 function 中可以靈活處理ref。
函數式元件
在 Vue 2 中,函數式元件有兩個主要應用場景:
作為性能優化,因為它們的初始化速度比有狀态元件快得多
傳回多個根節點
然而Vue 3對有狀态元件的性能進行了提升,與函數式元件的性能相差無幾。此外,有狀态元件現在還包括傳回多個根節點的能力。是以,建議隻使用有狀态元件。
結合<template>的函數式元件:
functional 移除
将 props 的所有引用重命名為 $props,attrs 重命名為 $attrs。
函數寫法:
相較于 Vue 2.x 有三點變化:
所有的函數式元件都是用普通函數建立的,換句話說,不需要定義 { functional: true } 元件選項。
export default導出的是一個函數,函數有兩個參數:
props
context(上下文):context是一個對象,包含attrs、slot、emit屬性
h函數需要全局導入
異步元件需要 defineAsyncComponent 方法來建立
異步元件的導入需要使用輔助函數defineAsyncComponent來進行顯式聲明
帶選項異步元件,component 選項重命名為 loader
(新增)元件事件需要在 emits 選項中聲明()
強烈建議使用 emits 記錄每個元件所觸發的所有事件。
因為移除了 v-on.native 修飾符。任何未聲明 emits 的事件監聽器都會被算入元件的 $attrs 并綁定在元件的根節點上。
如果emit的是原生的事件(如,click),就會存在兩次觸發。
一次來自于$emit的觸發;
一次來自于根元素原生事件監聽器的觸發;
(emits 1.更好的記錄已發出的事件,2.驗證抛出的事件)
渲染函數API
h是全局導入,而不是作為參數傳遞給渲染函數
在 2.x 中,render 函數會自動接收 h 函數作為參數
在 3.x 中,h 函數需要全局導入。由于 render 函數不再接收任何參數,它将主要在 setup() 函數内部使用。可以通路在作用域中聲明的響應式狀态和函數,以及傳遞給 setup() 的參數
移除$listeners整合到 $attrs
包含了父作用域中的(不含emits的) v-on 事件監聽器。它可以通過 v-on="$listeners" 傳入内部元件
$attrs包含class&style
在vue2中,關于父元件使用子元件有這樣一個原則:
預設情況下父作用域的不被認作 props 的 attribute 綁定 (attribute bindings) 将會“回退”且作為普通的 HTML attribute 應用在子元件的根元素上
這句話的意思是,父元件調用子元件時,給子元件錨點标簽添加的屬性中,除了在子元件的props中聲明的屬性,其他屬性會自動添加到子元件根元素上。
為此,vue添加了inheritAttrs = false,這些預設行為将會被去掉,通過執行個體 property $attrs 可以讓這些 attribute 生效,且可以通過 v-bind 顯性的綁定到非根元素上。
自定義元素檢測在編譯時執行
自定義元素互動
Vue 2中,通過 Vue.config.ignoredElements 配置自定義元素
Vue 3 通過app.config.isCustomElement
Vue 3.x 對 is做了新的限制
當在 Vue 保留的 component标簽上使用is時,它的行為将與 Vue 2.x 中的一緻
當在不同元件标簽上使用is時,is會被當做一個不同的prop;
當在普通的 HTML 元素上使用is,is将會被當做元素的屬性。
新增了v-is,專門來實作在普通的 HTML 元素渲染元件。
destroyed 生命周期選項被重命名為 unmounted
beforeDestroy 生命周期選項被重命名為 beforeUnmount
[外鍊圖檔轉存失敗,源站可能有防盜鍊機制,建議将圖檔儲存下來直接上傳(img-awWIzouv-1637307558259)(assets/vue3/img.png)]
整體來看其實變化不大,使用setup代替了之前的beforeCreate和created,其他生命周期名字有些變化,功能都是沒有變化的
Props 的預設值函數不能通路this
替代方案:
把元件接收到的原始 prop 作為參數傳遞給預設函數;
inject API 可以在預設函數中使用。
自定義指令 API 與元件生命周期一緻
綁定元件的執行個體從 Vue 2.x 的vnode.context移到了binding.instance中
data 選項應始終被聲明為一個函數
data 元件選項聲明不再接收 js 對象,隻接受函數形式的聲明。
當合并來自 mixin 或 extend 的多個 data 傳回值時,data現在變為淺拷貝形式(隻合并根級屬性)。
vue2
vue3
過渡的 class 名更改(過渡類名 v-enter 修改為 v-enter-from、過渡類名 v-leave 修改為 v-leave-from。)
transition-group 不再需要設定根元素( 不再預設渲染根元素,但仍可以使用 tag prop建立一個根元素。)
偵聽數組(當偵聽一個數組時,隻有當數組被替換時才會觸發回調。如果你需要在數組改變時觸發回調,必須指定 deep 選項。)
已挂載的應用不會取代它所挂載的元素(在vue2中,當挂載一個具有 template 的應用時,被渲染的内容會替換我們要挂載的目标元素。在 Vue 3.x 中,被渲染的應用會作為子元素插入,進而替換目标元素的 innerHTML)
生命周期 hook: 事件字首改為 vnode-(監聽子元件和第三方元件的生命周期)
不再支援使用數字 (即鍵碼) 作為 v-on 修飾符,vue3建議使用按鍵alias(别名)作為v-on的修飾符。
vue3将移除且不再支援 filters,如果需要實作過濾功能,建議通過method或computed屬性來實作(如果需要使用全局過濾器vue3提供了globalProperties。我們可以借助globalProperties來注冊全局過濾, 全局過濾器裡面定義的隻能是method。)
内聯模闆 (inline-template attribute移除)
$children(如果需要通路子元件執行個體,建議使用 $refs)
propsData 選項之前用于在建立 Vue 執行個體的過程中傳入 prop,現在它被移除了。如果想為 Vue 3 應用的根元件傳入 prop,使用 createApp 的第二個參數。
全局函數 set 和 delete 以及執行個體方法 $set 和 $delete。基于代理的變化檢測不再需要它們了。
@vue/compat (即“遷移建構版本”) 是一個 Vue 3 的建構版本,提供了可配置的相容 Vue 2 的行為。
該建構版本預設運作在 Vue 2 的模式下——大部分公有 API 的行為和 Vue 2 一緻,僅有一小部分例外。使用在 Vue 3 中發生改變或被廢棄的特性時會抛出運作時警告。一個特性的相容性也可以基于單個元件進行開啟或禁用。
已知的限制:
基于vue2内部API或文檔中未記載行為的依賴。最常見的情況就是使用 VNodes 上的私有 property。如果你的項目依賴諸如 Vuetify、Quasar 或 Element UI 等元件庫,那麼最好等待一下它們的 Vue 3 相容版本。
對IE11的支援:Vue 3 已經官方放棄對 IE11 的支援。如果仍然需要支援 IE11 或更低版本,那你仍需繼續使用 Vue 2。
服務端渲染:該遷移建構版本可以被用于服務端渲染,但是遷移一個自定義的服務端渲染設定有更多工作要做。大緻的思路是将 vue-server-renderer 替換為 @vue/server-renderer。Vue 3 不再提供一個包渲染器,推薦使用 Vite 以支援 Vue 3 服務端渲染。