Привет, Хабр!
Совсем скоро должна выйти новая версия Vue.js — 2.6. Под катом вы найдете обзор новых фич следующей версии, включая новый синтаксис слотов, Vue.observable() и много чего еще!

Это одно из самых значимых изменений. Оно включает в себя:
Проще всего это понять на примере:
Как использовались scoped slots в версии Vue@2.5.22:
Как можно теперь:
Для дефолтного слота можно применить специальный синтаксис, если не используются именованные слоты:
И вот сокращение для именованных слотов:
Новую директиву можно использовать и без каких-либо scope-переменных, но тогда слот все-равно попадет в $scopedSlots родителя.
Ссылки:
Если вы хотите динамический аргумент для v-bind или v-on, то во Vue@2.5.22 у вас есть только один вариант:
Но у него есть пара недостатков:
Чтобы избавиться от них, Vue@2.6.0 представляет новый синтаксис:
Примеры использования:
Ссылки:
Раньше, чтобы создать реактивный объект, нужно было засунуть его внутрь инстанса vue-компонента. Теперь у нас есть отдельный метод, который делает объект реактивным — Vue.observable().
Реактивный объект можно спокойно использовать в render- и computed-функциях.
Пример использования:
В новом обновлении vue-server-renderer изменил стратегию загрузки данных для SSR.
Раньше нам советовали вызывать методы asyncData() у компонентов, полученных через router.getMatchedComponents().
В новой версии появился специальный метод у компонентов — serverPrefetch(). vue-server-renderer вызовет его у каждого компонента и дождется решения возвращенных промисов:
Чтобы узнать, когда завершилось ожидание всех serverPrefetch() и приложение завершило свой рендеринг, в контексте функции серверного рендера появилась возможность добавить хук rendered():
При компиляции html в render-функцию vue-template-compiler может выдать ошибки. Раньше Vue выводил описание ошибки без ее местоположения, теперь новая версия будет показывать, где она находится.
Пример:
Ошибка vue-template-compiler@2.5.22:
Новый вывод ошибки vue-template-compiler@2.6.0:
Теперь Vue может ловить даже асинхронные ошибки в хуках жизненного цикла и обработчиках событий.
Пример:
Ошибка после маунта:
Ошибка после клика:
В новой версии добавилась еще одна сборка Vue — vue.esm.browser.js. Она предназначена для браузеров, поддерживающих ES6 Modules.
Ее особенности:
Пример использования:
Если честно, мне бы хотелось видеть еще одну сборку — такую же, как vue.esm.browser.js, но без компилятора HTML. Тогда я бы смог подвозить браузерам с ES6 Modules более свежий код, когда компилирую шаблоны при сборке.
У директивы v-bind есть специальный модификатор — .prop. Посмотреть, что он делает, можно вот тут в документации. Сам я ни разу его не использовал и не представляю себе случай, когда его стоит применить.
Для него теперь есть специальное сокращение: вместо записи v-bind:someProperty.prop=«foo» можно писать .someProperty=«foo».
Пример:
Как было во Vue@2.5.22:
Как можно во Vue@2.6.0:
Тут все просто: если вы переопределите метод toString() у объекта, то Vue при отображении станет использовать его вместо JSON.stringify().
Пример:
В версии Vue@2.5.22 мы увидим на экране:
В версии Vue@2.6.0:
В новой версии v-for может работать с любыми объектами, которые реализуют iterable protocol, например Map или Set. Правда, для Map и Set в версии 2.X не будет поддерживаться реактивность.
Пример:
Посмотреть все новые фишки в деле можно прямо сейчас, установив бета-версию Vue:
Если вы компилируете vue-файлы при сборке или используете SSR, то не забудьте добавить vue-template-compiler и vue-server-renderer такой же версии:
Обновление: Vue 2.6 вышел официально, тут можно почитать пост Евана.
Спасибо, что дочитали статью до конца!
Совсем скоро должна выйти новая версия Vue.js — 2.6. Под катом вы найдете обзор новых фич следующей версии, включая новый синтаксис слотов, Vue.observable() и много чего еще!

1. Новый синтаксис для scoped slots
Это одно из самых значимых изменений. Оно включает в себя:
- Новую директиву v-slot, объединяющую slot и slot-scope
- Сокращение для использования именованных scoped slots
Проще всего это понять на примере:
Как использовались scoped slots в версии Vue@2.5.22:
<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 используется прямо на родителе --> <TestComponent v-slot="{ message }"> <div> {{ `Default slot with message: ${message}` }} </div> </TestComponent> </template>
И вот сокращение для именованных слотов:
<template> <TestComponent> <!-- # - это сокращение для v-slot: --> <template #text="{ text }"> <div> {{ `Named slot with text: ${text}` }} </div> </template> </TestComponent> </template>
Новую директиву можно использовать и без каких-либо scope-переменных, но тогда слот все-равно попадет в $scopedSlots родителя.
Ссылки:
- Новый синтаксис v-slot
- Сокращение для v-slot
2. Динамический аргумент директивы
Если вы хотите динамический аргумент для v-bind или 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 с динамическим ключом --> <div v-bind:[key]="value"></div> <!-- сокращение v-bind с динамическим ключом --> <div :[key]="value"></div> <!-- v-on с динамическим событием --> <div v-on:[event]="handler"></div> <!-- сокращение v-on с динамическим событием --> <div @[event]="handler"></div> <!-- v-slot с динамическим именем --> <TestComponent> <template v-slot:[name]> Hello </template> </TestComponent> <!-- сокращение v-slot с динамическим именем --> <TestComponent> <template #[name]> Cool slot </template> </TestComponent> </div> </template>
Ссылки:
3. Создание реактивных объектов с помощью Vue.observable()
Раньше, чтобы создать реактивный объект, нужно было засунуть его внутрь инстанса vue-компонента. Теперь у нас есть отдельный метод, который делает объект реактивным — Vue.observable().
Реактивный объект можно спокойно использовать в render- и computed-функциях.
Пример использования:
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 вызовет его у каждого компонента и дождется решения возвращенных промисов:
<template> <div v-if="item"> {{ item.name }} </div> </template> <script> export default { // Вызовется на сервере async serverPrefetch() { await this.fetchItem(); }, computed: { item() { return this.$store.state.item; }, }, // Вызовется на клиенте mounted() { if (!this.item) { this.fetchItem(); } }, methods: { async fetchItem() { await this.$store.dispatch('fetchItem'); }, }, }; </script>
Чтобы узнать, когда завершилось ожидание всех serverPrefetch() и приложение завершило свой рендеринг, в контексте функции серверного рендера появилась возможность добавить хук rendered():
/* Упрощенный 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 = () => { // Передаем состояние хранилища после завершения всех serverPrefetch() context.state = store.state; }; resolve(app); }, reject); });
5. Улучшенный вывод ошибок компилятора
При компиляции html в render-функцию 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>
Ошибка после маунта:
[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 — vue.esm.browser.js. Она предназначена для браузеров, поддерживающих ES6 Modules.
Ее особенности:
- Содержит компилятор HTML в render-функцию
- Использует синтаксис ES6 Modules
- Содержит нетранспилированный код
Пример использования:
<html lang="en"> <head> <title>Document</title> </head> <body> <div id="app"> {{ message }} </div> <script type="module"> // Раньше приходилось использовать vue.esm.js, // который содержал транспилированный код, // весил чуть больше и работал чуть медленнее import Vue from 'path/to/vue.esm.browser.js'; new Vue({ el: '#app', data() { return { message: 'Hello World!', }; }, }); </script> </body> </html>
Если честно, мне бы хотелось видеть еще одну сборку — такую же, как vue.esm.browser.js, но без компилятора HTML. Тогда я бы смог подвозить браузерам с ES6 Modules более свежий код, когда компилирую шаблоны при сборке.
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 protocol, например Map или Set. Правда, для Map и Set в версии 2.X не будет поддерживаться реактивность.
Пример:
/* 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:
npm i vue@2.6.0-beta.3
Если вы компилируете vue-файлы при сборке или используете SSR, то не забудьте добавить vue-template-compiler и vue-server-renderer такой же версии:
npm i vue-template-compiler@2.6.0-beta.3 vue-server-renderer@2.6.0-beta.3
Обновление: Vue 2.6 вышел официально, тут можно почитать пост Евана.
Спасибо, что дочитали статью до конца!
