在這篇文章中,將會介紹新版本的新特性, 比如slots
的新語法,Vue.observable()
等等
1. Scoped slots(作用域插槽)的新語法
這是一個比較重大的改變,包含的有:
- v-slot新指令,結合了
slot
和slot-scope
的功能 scoped slots
的簡寫
之前在Vue@2.5.22中是這樣使用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
中使用動態變數,在Vue@2.5.22中:
<div v-bind="{ [key]: value }"></div>
<div v-on="{ [event]: handler }"></div>
複製程式碼
但是這個例子有幾個缺點:
-
不是所有人都知道在
v-bind / v-on
中可以使用動態變數名 -
vue-template-compier
生成了低效的程式碼 -
v-slot
沒有類似的使用物件的語法
為了解決這些問題,Vue@2.6.0
引入了一個新語法:
<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. server端獲取資料
在新的升級版本中,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>
複製程式碼
在vue-template-compiler@2.5.22中:
Error compiling template:
<div>
<template key="test-key">
{{ message }}
</template>
</div>
- <template> cannot be keyed. Place the key on real elements instead.
複製程式碼
在vue-template-compiler@2.6.0中:
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"
在Vue@2.5.22中:
<template>
<div>
<div v-bind:textContent.prop="'Important text content'" />
<! - 簡寫版本 ->
<div: textContent.prop="'Important text content'" />
</ div>
</ template>
複製程式碼
Vue@2.6.0:
<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>
複製程式碼
Vue@2.5.22中顯示:
{ "value": "qwerty" }
複製程式碼
Vue@2.6.0:
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>
複製程式碼