Vue.js 2.6嚐鮮

qbylucky發表於2019-02-05

Vue.js 2.6嚐鮮
昨天Vue 2.6 "Macross" 釋出了,同時也是Vuejs五週年~

在這篇文章中,將會介紹新版本的新特性, 比如slots的新語法,Vue.observable()等等

1. Scoped slots(作用域插槽)的新語法

這是一個比較重大的改變,包含的有:

  • v-slot新指令,結合了slotslot-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>
複製程式碼

Vue.js 2.6嚐鮮

相關文章