Vue.js 2.6嚐鮮

昨天Vue 2.6 "Macross" 釋出了,同時也是Vuejs五週年~
在這篇文章中,將會介紹新版本的新特性, 比如 slots
的新語法, Vue.observable()
等等
1. Scoped slots(作用域插槽)的新語法
這是一個比較重大的改變,包含的有:
- v-slot新指令,結合了
slot
和slot-scope
的功能 -
scoped slots
的簡寫
之前在 [email protected] 中是這樣使用 scoped-slots
的:
<template> <TestComponent> <! - 預設 scoped slot -> <div slot-scope="{message}"> {{`Default slot with message: ${message}`}} </ div> <! - 具名 scoped slot -> <div slot="text" slot-scope="{text}"> {{`Named slot with text: ${text}`}} </ div> </ TestComponent> </ template> 複製程式碼
現在是這樣的:
<template> <TestComponent> <! - 預設 scoped slot -> <template v-slot="{message}"> <div> {{`Default slot with message: ${message}`}} </ div> </ template> <! - 具名 scoped slot -> <template v-slot:text="{text}"> <div> {{`Named slot with text: ${text}`}} </ div> </ template> </ TestComponent> </ template> 複製程式碼
預設插槽:
<template> <! - v-slot is used directly on the parent -> <TestComponent v-slot="{message}"> <div> {{`Default slot with message: ${message}`}} </ div> </ TestComponent> </ template> 複製程式碼
具名插槽:
<template> <TestComponent> <! - # 簡寫: -> <template #text="{text}"> <div> {{`Named slot with text: ${text}`}} </ div> </ template> </ TestComponent> </ template> 複製程式碼
新版中,可以不使用任何作用域插槽變數,但是仍然可以通過父元件的 $scopedSlots
去引用到
2. 動態引數指令
如果我們想在 v-bind
or v-on
中使用動態變數,在 [email protected] 中:
<div v-bind="{ [key]: value }"></div> <div v-on="{ [event]: handler }"></div> 複製程式碼
但是這個例子有幾個缺點:
-
不是所有人都知道在
v-bind / v-on
中可以使用動態變數名 -
vue-template-compier
生成了低效的程式碼 -
v-slot
沒有類似的使用物件的語法
為了解決這些問題, [email protected]
引入了一個新語法:
<div v-bind:[key]="value"></div> <div v-on:[event]="handler"></div> 複製程式碼
舉個例子:
<template> <div> <! - v-bind 動態key -> <div v-bind:[key]="value"> </ div> <! - 簡寫 -> <div :[key]="value"> </ div> <! - v-on 動態事件,event變數 -> <div v-on:[event]="handler"> </ div> <! - 簡寫 -> <div @[event]="handler"> </ div> <! - v-slot 動態名字 -> <TestComponent> <template v-slot:[name]> Hello </ template> </ TestComponent> <! - 簡寫 -> <TestComponent> <template #[name]> Cool slot </ template> </ TestComponent> </ div> </ template> 複製程式碼
3. 使用Vue.observable()建立一個響應物件
之前,建立一個響應物件,必須在一個Vue例項中配置。現在我們可以在Vue例項外部,通過使用 Vue.observable(data)
建立,如下:
import vue from vue; const state = Vue.observable ({ counter: 0, }); export default { render () { return ( <div> {state.counter} <button v-on:click={() => {state.counter ++; }}> Increment counter </ button> </ div> ); }, }; 複製程式碼
4. 從伺服器下載資料
在新的升級版本中, vue-server-renderer
改變了SSR的資料載入策略。
之前,我們推薦使用 asyncData ()
在 router.getMatchedComponents ()
方法中獲取的元件中,獲取資料。
新版本中有一個特別的元件方法: serverPrefetch()
。vue-server-renderer會在每個元件中呼叫它,它會返回一個promise。
<template> <div v-if="item"> {{item.name}} </ div> </ template> <script> export default { // Call on the server async serverPrefetch () { await this.fetchItem(); }, computed: { item () { return this.$store.state.item; }, }, // Call on client mounted () { if (!this.item) { this.fetchItem(); } }, methods: { async fetchItem () { await this.$store.dispatch('fetchItem'); }, }, }; </ script> 複製程式碼
在 serverPrefetch()
執行之後,我們需要知道應用在什麼時候渲染完成,在server render 上下文中,我們可以使用 rendered()
鉤子方法。
/ * Simplified entry-server.js * / import {createApp} from './app'; export default context => new Promise ((resolve, reject) => { const {app, router, store} = createApp(); const {url} = context; router.push(url); router.onReady(() => { context.rendered = () => { context.state = store.state; }; resolve (app); }, reject); }); 複製程式碼
5. 改進的錯誤輸出
在 render
方法中編譯html, vue-template-compiler
可能會產生錯誤。在之前,Vue會產生一個沒有位置的錯誤描述。新版本中會展示這個錯誤出現在哪裡,比如:
<template> <div> <template key="test-key"> {{ message }} </template> </div> </template> 複製程式碼
在[email protected]中:
Error compiling template: <div> <template key="test-key"> {{ message }} </template> </div> - <template> cannot be keyed. Place the key on real elements instead. 複製程式碼
在[email protected]中:
Errors compiling template: <template> cannot be keyed. Place the key on real elements instead. 1| 2|<div> 3|<template key="test-key"> |^^^^^^^^^^^^^^ 4|{{ message }} 5|</template> 複製程式碼
6. 捕捉非同步錯誤
現在 Vue 可以在生命週期方法鉤子和事件方法中捕捉到非同步錯誤異常。比如:
/ * TestComponent.vue * / <template> <div @click="doSomething()"> Some message </ div> </ template> <script> export default { methods: { async doSomething () { await this.$nextTick (); throw new Error ('Another Error'); }, }, async mounted () { await this.$nextTick (); throw new Error ('Some Error'); }, }; </ script> 複製程式碼
mount後錯誤:
[Vue warn]: Error in mounted hook (Promise/async): "Error: Some Error" 複製程式碼
點選事件後錯誤:
[Vue warn]: Error in v-on handler (Promise/async): "Error: Another Error" 複製程式碼
7. ESM 瀏覽器中的新版構建
新版本中,增加了一個 vue.esm.browser.js 。它是為了支援 ES6 Modules 的瀏覽器設計的。
特性:
- 在render函式中,包含HTML編譯器
- 使用ES6模組語法
- 包含非副本程式碼(non-transcript)
舉例:
<html lang="en"> <head> <title> Document </ title> </ head> <body> <div id="app"> {{message}} </ div> <script type="module"> import Vue from 'path/to/vue.esm.browser.js'; new Vue {{ el: '#app', data () { return { message: 'Hello World!', }; }, }); </ script> </ body> </ html> 複製程式碼
8. v-bind.prop簡寫
v-bind
指令有一個特殊的修飾符--- .prop
。你可以在文件中檢視具體用法。我自己從沒使用過,暫時也想不到在什麼時候使用。
現在有一個簡寫方式,對於 v-bind:someProperty.prop="foo"
, 可以寫成 .someProperty="foo"
在[email protected]中:
<template> <div> <div v-bind:textContent.prop="'Important text content'" /> <! - 簡寫版本 -> <div: textContent.prop="'Important text content'" /> </ div> </ template> 複製程式碼
[email protected]:
<template> <div .textContent="'Important text content'" /> </template> 複製程式碼
9. 支援自定義toString()
規則很簡單:如果重寫了物件的 toString()
方法,顯示的時候,Vue將使用它,而不是 JSON.stringify()
舉例:
/ * TestComponent.vue * / <template> <div> {{message}} </ div> </ template> <script> export default { data () { return { message: { value: 'qwerty', toString () { return 'Hello Habr!'; }, }, }; }, }; </ script> 複製程式碼
[email protected]中顯示:
{ "value": "qwerty" } 複製程式碼
[email protected]:
Hello Habr! 複製程式碼
10. v-for和可迭代物件
在新版本中, v-for
可以遍歷任何實現了 iterable協議 的物件,比如 Map , Set 。
在 2.X 版本中,Map和Set, 不支援資料響應。
舉例:
/ * TestComponent.vue * / <template> <div> <div v-for="item in items" :key="item" > {{item}} </ div> </ div> </ template> <script> export default { data () { return { items: new Set([4, 2, 6]), }; }, }; </ script> 複製程式碼
