轉(zhuǎn)自尤大大
昨天剛剛慶祝了 Vue 發(fā)布五周年,今天我們趁熱打鐵在年三十發(fā)布了 Vue 2.6 “Macross”靶橱,祝大家新春快樂!
在過去一年里面我們花了大量的精力在新版的 CLI 和 3.0 的設(shè)計(jì)/原型調(diào)研上,因此 Vue 2.x 相對(duì)地已經(jīng)很久沒有重大更新了。差不多是時(shí)候了肺蔚!這次的 2.6 包含了一些相當(dāng)有份量的更新,我們?cè)谶@里會(huì)討論一些亮點(diǎn)——具體細(xì)節(jié)還請(qǐng)移步完整的 release note勾怒。
Slots:新語法婆排,性能優(yōu)化声旺,準(zhǔn)備接軌 3.0
Slot /插槽 是 Vue 組件的一個(gè)重要機(jī)制笔链,因?yàn)樗沟猛耆怦畹慕M件之間可以靈活地被組合。在 3.0 的原型開發(fā)過程中腮猖,我們發(fā)現(xiàn)了一些可以進(jìn)一步改善現(xiàn)有的 slot 機(jī)制的方法鉴扫。這里面有些可能會(huì)需要少量破壞性的改動(dòng),但也有一些可以以完全向后兼容的方式被引入 2.x澈缺。對(duì)于那些需要破壞性改動(dòng)的改進(jìn)坪创,我們也盡量通過在 2.x 中引入完全兼容的改動(dòng)來漸進(jìn)地跟 3.0 的 API 接軌。
新語法
首先姐赡,我們?yōu)?slot 引入了一套全新的模版語法莱预。語法改動(dòng)是我們很少做的事情(這也是 3.0 唯一計(jì)劃改的語法),所以我們嘗試了多種不同的設(shè)計(jì)项滑,并且進(jìn)行了大量的討論依沮。最終我們敲定了基于新的 v-slot 指令的語法(具體設(shè)計(jì)細(xì)節(jié)見 RFC)。這里是兩個(gè)簡(jiǎn)略的例子:
默認(rèn)作用域插槽 (default scoped slot)
<my-component v-slot="{ msg }">
?{{ msg }}</my-component>
具名插槽 (named slots)
<my-component>
?<template v-slot:header>
? ?<p>Header</p>
?</template>
?<template v-slot:item="{ data }">
? ?<h2>{{ data.title }}</h2>
? ?<p>{{ data.text }}</p>
?</template>
?<template v-slot:footer>
? ?<p>Footer</p>
?</template>
</my-component>
新語法將普通的插槽 (slot) 和作用域插槽 (scoped slot) 統(tǒng)一在一個(gè)指令語法下,并在整體上強(qiáng)調(diào)明確性 (explicitness) 和一致性 (consistency)危喉。同時(shí)宋渔,由于新語法和舊語法完全兼容,這使得我們可以在 2.6 中發(fā)布它辜限。
如果你已經(jīng)熟悉現(xiàn)有的 slot 語法并且英語過關(guān)皇拣,我們建議你完整地閱讀 RFC 來更好地理解新語法為什么這樣設(shè)計(jì)。如果你對(duì)于 slot 并不熟悉薄嫡,那么建議你直接看更新過的文檔(或是等勾股更新中文翻譯)氧急。
性能優(yōu)化
在 3.0 中我們希望實(shí)現(xiàn)的另一個(gè)關(guān)于 slot 的改進(jìn)就是統(tǒng)一 slot 和 scoped slot 的內(nèi)部實(shí)現(xiàn),從而獲得更好的性能優(yōu)化毫深。普通的 slot 是在父組件的渲染函數(shù)中被生成的态蒂,因此當(dāng)一個(gè)普通的 slot 所依賴的數(shù)據(jù)發(fā)生變化時(shí),首先觸發(fā)的是父組件的更新费什,然后新的 slot 內(nèi)容被傳到子組件钾恢,觸發(fā)子組件更新。相比之下鸳址,scoped slot 在編譯時(shí)生成的是一個(gè)函數(shù)瘩蚪,這個(gè)函數(shù)被傳入子組件之后會(huì)在子組件的渲染函數(shù)中被調(diào)用。這意味著 scoped slot 的依賴會(huì)被子組件收集稿黍,那么當(dāng)依賴變動(dòng)時(shí)就只會(huì)直接觸發(fā)子組件更新了疹瘦。2.6 中我們又引入了另一個(gè)優(yōu)化:如果子組件只使用了 scoped slot,那么父組件自身依賴變動(dòng)時(shí)巡球,不會(huì)再?gòu)?qiáng)制子組件更新言沐。這個(gè)優(yōu)化使得父子組件之間的依賴即使在存在 slot 的情況下依然完全解耦,從而保證最優(yōu)的整體更新效率酣栈。(對(duì)比之下 React 使用 render props 時(shí)絕大部分情況下都會(huì)觸發(fā)父子組件一起更新)
除此之外:
1险胰、所有使用新的 v-slot 語法的 slot 都會(huì)被編譯為 scoped slot。這意味著所有使用新語法的 slot 代碼都會(huì)獲得上述的性能優(yōu)化矿筝;
2起便、所有的非 scoped slot 現(xiàn)在也被以函數(shù)的形式暴露在 this.$scopedSlots 上。如果你是直接用 render 函數(shù)的用戶窖维,你現(xiàn)在可以完全拋棄 this.$slots 而全部用 this.$scopedSlots 來處理所有的 slots 了榆综。(3.0 中 this.$slots 將會(huì)直接暴露函數(shù),取代 this.$scopedSlots)
3铸史、3.0 中將不再有普通 slot 和 scoped slot 的區(qū)分——所有的 slot 都使用統(tǒng)一的語法鼻疮,使用統(tǒng)一的內(nèi)部實(shí)現(xiàn),獲得同樣的性能優(yōu)化琳轿。
異步錯(cuò)誤處理
Vue 的內(nèi)置錯(cuò)誤處理機(jī)制(組件中的 errorCaptured 鉤子和全局的 errorHandler 配置項(xiàng))現(xiàn)在也會(huì)處理 v-on 偵聽函數(shù)中拋出的錯(cuò)誤了判沟。另外震贵,如果你組件的生命周期鉤子或是實(shí)踐偵聽函數(shù)中有異步操作,那么可以通過返回一個(gè) Promise 的方式來讓 Vue 處理可能存在的異步錯(cuò)誤水评。如果你用了 async/await猩系,那么就更簡(jiǎn)單了,因?yàn)?async 函數(shù)默認(rèn)返回 Promise:
export default {
?async mounted() {
? ?// 這里拋出的異步錯(cuò)誤會(huì)被 errorCaptured 或是
? ?// Vue.config.errorHandler 鉤子捕獲到
? ?this.posts = await api.getPosts()
?}
}
動(dòng)態(tài)指令參數(shù)
指令的參數(shù)現(xiàn)在可以接受動(dòng)態(tài)的 JavaScript 表達(dá)式:
<div v-bind:[attr]="value"></div>
<div :[attr]="value"></div>
<button v-on:[event]="handler"></button>
<button @[event]="handler"></button>
<my-component>
?<template v-slot:[slotName]>
? ?Dynamic slot name ?</template>
</my-component>
更多細(xì)節(jié)參見 RFC中燥。該語法一個(gè)方便的特性是如果表達(dá)式的值是 null 則綁定/偵聽器會(huì)被移除寇甸。
組件庫(kù)的作者需要注意:該語法需要 2.6 以上版本的 runtime 的配合。如果你發(fā)布的是預(yù)編譯過的組件疗涉,并且想要保持跟 2.6 之前版本的兼容拿霉,不要使用此功能。
編譯警告位置信息
2.6 開始咱扣,所有的編譯器警告都包含了源碼位置信息绽淘。這使得我們可以生成更有用的警告信息:
顯式創(chuàng)建響應(yīng)式對(duì)象
2.6 引入了一個(gè)新的全局 API,可以用來顯式地創(chuàng)建響應(yīng)式對(duì)象:
const reactiveState = Vue.observable({
count: 0
})
生成的對(duì)象可以直接用在計(jì)算屬性 (computed property) 和 render 函數(shù)中闹伪,并會(huì)在被改動(dòng)時(shí)觸發(fā)相應(yīng)的更新沪铭。
SSR 數(shù)據(jù)預(yù)抓取
新的 serverPrefetch 鉤子 使得任意組件都可以在服務(wù)端渲染時(shí)請(qǐng)求異步的數(shù)據(jù)(不再限制于路由組件)。這使得整體的數(shù)據(jù)預(yù)抓取方案可以更為靈活偏瓤,并且可以和路由解耦杀怠。Nuxt 和 vue-apollo 等項(xiàng)目已經(jīng)計(jì)劃使用此特性來簡(jiǎn)化其內(nèi)部實(shí)現(xiàn)以及提供新的能力。
可直接在瀏覽器中引入的 ES Modules 構(gòu)建文件
Vue 之前版本的 ES Modules 構(gòu)建文件是針對(duì)打包工具的厅克,因此里面包含了一些需要在構(gòu)建時(shí)替換掉的環(huán)境變量赔退,從而導(dǎo)致無法直接在瀏覽器中使用。2.6 包含了一個(gè)可以直接在瀏覽器導(dǎo)入的版本:
import Vue from 'https://unpkg.com/vue/dist/vue.esm.browser.js'
new Vue({
// ...
})
重要的內(nèi)部改動(dòng)
nextTick 重新調(diào)整為全部使用 Microtask
在 2.5 當(dāng)中我們引入了一個(gè)改動(dòng)证舟,使得當(dāng)一個(gè) v-on DOM 事件偵聽器觸發(fā)更新時(shí)硕旗,會(huì)使用 Macrotask 而不是 Microtask 來進(jìn)行異步緩沖。這原本是為了修正一類瀏覽器的特殊邊際情況導(dǎo)致的 bug 才引入的女责,但這個(gè)改動(dòng)本身卻導(dǎo)致了更多其它的問題漆枚。在 2.6 里面我們對(duì)于原本的邊際情況找到了更簡(jiǎn)單的 fix,因此這個(gè) Macrotask 的改動(dòng)也就沒有必要了±鹬瘢現(xiàn)在 nextTick 將會(huì)統(tǒng)一全部使用 Microtask浪读。如果你對(duì)具體的細(xì)節(jié)感興趣,可以看這里辛藻。
this.$scopedSlots 函數(shù)統(tǒng)一返回?cái)?shù)組
(此改動(dòng)只影響使用 render 函數(shù)的用戶)在 render 函數(shù)中,傳入的 scoped slot 以函數(shù)的形式被暴露在 this.$scopedSlots 上面互订。在之前的版本中吱肌,這些函數(shù)會(huì)基于父組件傳入的內(nèi)容不同而返回單個(gè) VNode 或是一個(gè) VNode 的數(shù)組。這是當(dāng)初實(shí)現(xiàn)時(shí)的一個(gè)疏漏仰禽,導(dǎo)致了 scoped slot 函數(shù)的返回值類型是不確定的氮墨。2.6 當(dāng)中纺蛆,所有的 scoped slot 函數(shù)都只會(huì)返回 VNode 數(shù)組或是 undefined。如果你的現(xiàn)有代碼中使用了 this.$scopedSlots 并且沒有處理可能返回?cái)?shù)組的情況规揪,那么可能會(huì)需要進(jìn)行相應(yīng)的修正桥氏。更多細(xì)節(jié)參見這里。
致謝
感謝所有為這個(gè)版本貢獻(xiàn)了 PR 的 contributors猛铅,以及參與 RFC 討論的社區(qū)成員字支。
關(guān)注公眾號(hào)【grain先森】,回復(fù)關(guān)鍵詞 【18福利】奸忽,獲取為你準(zhǔn)備的年終福利堕伪,更多關(guān)鍵詞玩法期待你的探索~