Vue 3 официально не выпущен, но сопровождающий выпустил бета-версию, чтобы наши участники могли попробовать и оставить отзыв.
Если вам интересно, каковы основные функции и основные изменения в Vue 3, то я сосредоточусь на них в этом посте, предлагая вам создать простое приложение с помощью Vue 3 beta 9.
Я расскажу как можно больше нового, включая фрагменты, телепорты, Composition API и некоторые другие малоизвестные изменения. Я попытаюсь объяснить причину этой функции или изменения.
Статьи по теме Vue3:
- Как Vue3 Composition API заменяет Vue Mixins
- Извлечение и повторное использование логики в Vue3 Composition API
- Как создать один и тот же компонент в Vue2 и Vue3
- Предварительное исследование Vue Router в Vue3
что мы будем строить
Мы создадим простое приложение с функциональностью модального окна. Я выбрал его, потому что он удобно демонстрирует многие изменения в Vue 3.
Вот как приложение выглядит во включенном и выключенном состоянии, чтобы вы могли мысленно представить, что мы делаем:
Установка и настройка Vue 3
Вместо того, чтобы устанавливать Vue 3 напрямую, клонируйте проектvue-next-webpack-preview
, что даст нам минимальную настройку Webpack, включая Vue 3.
$ git clone https://github.com/vuejs/vue-next-webpack-preview.git vue3-experiment
$ cd vue3-experiment
$ npm i
После клонирования и установки модуля npm все, что нам нужно сделать, это удалить шаблон и создать новый.main.js
файл, чтобы мы могли создать наше приложение Vue 3 с нуля.
$ rm -rf src/*
$ touch src/main.js
Теперь запустим сервер разработки:
$ npm run dev
Создайте новое приложение Vue 3
Способ, которым мы запускаем новое приложение Vue, изменился, теперь нам нужно импортировать новыйcreateApp
метод вместо использования новогоVue()
.
Мы вызываем этот метод, передавая наш объект определения экземпляра Vue и присваивая возвращаемый объект переменнойapp
.
Далее мы будемapp
звонитьmount
и передайте селектор CSS, чтобы указать наш элемент монтирования, как в Vue 2.$mount
То же, что метод экземпляра.
// src/main.js
import { createApp } from "vue";
const app = createApp({
// 根实例定义
});
app.mount("#app");
Причина изменения
Как и в случае со старым API, любая глобальная конфигурация, которую мы добавляем (плагины, примеси, свойства прототипа и т. д.), навсегда изменит глобальное состояние. Например:
// src/main.js
// 影响两个实例
Vue.mixin({ ... })
const app1 = new Vue({ el: '#app-1' })
const app2 = new Vue({ el: '#app-2' })
В модульном тестировании это действительно проблема, так как сложно убедиться, что каждый тест изолирован от предыдущего.
В новом API вызовитеcreateApp
вернет новый экземпляр приложения, который не загрязнен какой-либо глобальной конфигурацией, примененной к другим экземплярам.
понять больше:Global API change RFC.
добавить государственную собственность
Наше модальное окно может находиться в одном из двух состояний - открыто или закрыто. Давайте использовать логическое свойство состоянияmodalOpen
чтобы управлять им, мы дадим ему начальное значениеfalse
.
В Vue 2 мы можем сделать это, создавdata
свойство и назначение объекта этому объекту для объявленияmodalOpen
свойства, такие как:
// src/main.js
const app = createApp({
data: {
modalOpen: false
}
});
Это больше не разрешено. Вместо этого данным должна быть назначена фабричная функция, которая возвращает объект состояния.
// src/main.js
const app = createApp({
data: () => ({
modalOpen: false
})
});
Причина изменения
Преимущество использования объектов вместо фабричных функций заключается, во-первых, в более простом синтаксисе; во-вторых, вы можете совместно использовать состояние верхнего уровня между несколькими корневыми экземплярами, например:
// src/main.js
const state = {
sharedVal: 0
};
const app1 = new Vue({ state });
const app2 = new Vue({ state });
// 影响两个实例
app1._data.sharedVal = 1;
Таких вариантов использования очень мало. Так как есть два типа объявлений, которые не подходят для новичков, было решено убрать эту возможность.
понять больше:Data object declaration removed RFC
Прежде чем продолжить, мы также добавим метод для переключенияmodalOpen
стоимость. Это ничем не отличается от Vue 2.
// src/main.js
const app = createApp({
data: () => ({
modalOpen: true
}),
methods: {
toggleModalState() {
this.modalOpen = !this.modalOpen;
}
}
});
использовать корневой компонент
Если вы сейчас зайдете в свой браузер и проверите консоль, вы увидите предупреждение «Компоненту не хватает функции рендеринга», потому что мы не определили шаблон для корневого экземпляра.
Лучшей практикой для Vue 2 является создание минимального шаблона для корневого экземпляра и создание компонента приложения, в котором будет объявлен основной тег приложения.
Давайте сделаем то же самое здесь.
$ touch src/App.vue
Теперь мы можем получить корневой экземпляр для рендеринга компонента. Разница в том, что в Vue 2 мы обычно используем для этого функцию рендеринга:
// src/main.js
import App from "./App.vue";
const app = createApp({
...
render: h => h(App)
});
app.mount("#app");
Мы все еще можем это сделать, но у Vue 3 есть более простой способ — сделатьApp
стать корневым компонентом. Для этого мы можем удалить определение корневого экземпляра и вместо этого передатьApp
компоненты.
// src/main.js
import App from "./App.vue";
const app = createApp(App);
app.mount("#app");
это означаетApp
Компоненты визуализируются не только корневым экземпляром, но и корневым экземпляром.
В ходе этого процесса мы удаляемapp
переменная для упрощения синтаксиса:
// src/main.js
createApp(App).mount("#app");
Теперь перейдем к корневому компоненту, давайте повторно добавим состояние и методы к этому компоненту:
// src/App.vue
<script>
export default {
data: () => ({
modalOpen: true
}),
methods: {
toggleModalState() {
this.modalOpen = !this.modalOpen;
}
}
};
</script>
Мы также создаем новый компонент для модальной функциональности:
$ touch src/Modal.vue
Теперь мы предоставим минимальный шаблон, включающий слоты контента. Это гарантирует возможность повторного использования нашего модального окна. Мы добавим больше к этому компоненту позже.
// src/Modal.vue
<template>
<div class="modal">
<slot></slot>
</div>
</template>
Несколько корневых шаблонов
Теперь давайте создадим шаблон для нашего корневого компонента. Мы создадим кнопку, чтобы открыть модальное окно, которое вызоветtoggleModalState
метод.
Мы также будем использовать только что созданный модальный компонент, который будет основан наmodalState
значение для рендеринга. Давайте также вставим в слот фрагмент текста в качестве контента.
// src/App.vue
<template>
<button @click="toggleModalState">Open modal</button>
<modal v-if="modalOpen">
<p>Hello, I'm a modal window.</p>
</modal>
</template>
<script>
import Modal from "./Modal.vue";
export default {
components: {
Modal
},
...
}
</script>
Заметили что-нибудь странное в этом шаблоне? Посмотри снова.
Правильно - есть два корневых элемента. В Vue 3 больше не обязательно иметь один корневой элемент благодаря функции, называемой фрагментами!
Рефакторинг с использованием Composition API
Флагманская особенность Vue 3 является композицией API. Этот новый API позволяет использовать васsetup
функциональность вместо использования свойств, добавленных в объект определения компонента для определения функциональности компонента.
Теперь давайте рефакторим компонент App, чтобы использовать Composition API.
Прежде чем объяснять код, дайте понять, что все, что мы делаем, это рефакторинг — компоненты будут функционировать одинаково. Также обратите внимание, что шаблон не изменился, потому что Composition API влияет только на то, как мы определяем функциональность компонента, а не на то, как мы его отображаем.
src/App.vue
<template>
<button @click="toggleModalState">Open modal</button>
<modal v-if="modalOpen">
<p>Hello, I'm a modal window.</p>
</modal>
</template>
<script>
import Modal from "./Modal.vue";
import { ref } from "vue";
export default {
setup () {
const modalState = ref(false);
const toggleModalState = () => {
modalState.value = !modalState.value;
};
return {
modalState,
toggleModalState
}
}
};
</script>
метод установки
Во-первых, обратите внимание, что мы импортировалиref
функция, которая позволяет нам определять реактивные переменныеmodalState
. Эта переменная эквивалентнаthis.modalState
.
toggleModalState
Метод — это обычная функция JavaScript. Однако учтите, что для измененияmodalState
значение, нам нужно изменить его подсвойствоvalue
. Это потому, что использованиеref
Созданная реактивная переменная инкапсулируется в объект. Это необходимо для сохранения их отзывчивости, так как они сохраняются по мере прохождения.
Наконец, мы начинаем сsetup
метод возвращаетmodalState
а такжеtoggleModalState
, так как это значения, которые передаются шаблону при его рендеринге.
Причина изменения
Помните, что Composition API не является изменением, так как он необязателен. Основная мотивация состоит в том, чтобы позволить лучшую организацию кода и повторное использование кода между компонентами (поскольку миксины по своей сути являются анти-шаблоном).
Если вы считаете, что нет необходимости рефакторить компонент App для использования Composition API в этом примере, вы правы. Однако, если это более крупный компонент или нам нужно разделить его функциональность с другими компонентами, то он вам пригодится.
Teleporting content
Если вы когда-либо создавали модальную функцию, вы знаете, что она обычно помещается в закрывающем</body>
перед этикеткой.
<body>
<div>
<!--main page content here-->
</div>
<!--modal here-->
</body>
Это сделано потому, что у модального окна обычно есть фон, который покрывает страницу, чтобы сделать это с помощью CSS, вам не нужно иметь дело с позиционированием родительского элемента и контекстом стека z-index, поэтому самое простое решение - поместить модальное окно в самое начало страницы. внизу ДОМ.
Но это создает проблему в Vue.js, который предполагает, что пользовательский интерфейс будет построен как единое дерево компонентов. Чтобы разрешить перемещение фрагментов дерева в другие места в DOM, в Vue 3 был добавлен новый.teleport
компоненты.
Чтобы использовать телепорт, нам сначала нужно добавить элемент на страницу, на которую мы хотим переместить модальное содержимое. мы пойдемindex.html
и установите идентификатор какmodal-wrapper
изdiv
Размещены рядом с элементом монтажа Vuue.
index.html
<body>
...
<div id="app"></div><!--Vue mounting element-->
<div id="modal-wrapper">
<!--modal should get moved here-->
</div>
</body>
Теперь вернемся кApp.vue
, мы оборачиваем модальное содержимое вteleport
в компоненте. Нам также необходимо указатьto
атрибут, которому назначается селектор запросов для идентификации целевого элемента, в данном случае#modal-wrapper
.
src/App.vue
<template>
<button @click="toggleModalState">Open modal</button>
<teleport to="#modal-wrapper">
<modal v-if="modalOpen">
<p>Hello, I'm a modal window.</p>
</modal>
</teleport>
</template>
Вот и все,teleport
Все, что находится внутри, будет отображаться в целевом элементе.
Излучение и события
Теперь давайте добавим кнопку в модальное окно, чтобы его можно было закрыть. Для этого мы добавим элемент кнопки в модальный шаблон и добавим обработчик щелчка, который генерируетclose
мероприятие.
src/Modal.vue
<template>
<div class="modal">
<slot></slot>
<button @click="$emit('close')">Dismiss</button>
</div>
</template>
Затем событие будет перехвачено родительским компонентом и переключитсяmodalState
значение, которое логически устанавливает его вfalse
и заставить окно закрыться.
src/App.vue
<template>
...
<modal
v-if="modalOpen"
@click="toggleModalState"
>
<p>Hello, I'm a modal window.</p>
</modal>
</teleport>
</template>
Пока эта функциональность такая же, как и во Vue 2. Однако теперь в Vue 3 рекомендуется использовать новыйemits
Параметры компонента явно объявляют события для компонента. Как и в случае с пропсами, вы можете просто создать массив строк для имени каждого события, которое будет генерировать компонент.
src/Modal.vue
<template>...</template>
<script>
export default {
emits: [ "close" ]
}
</script>
Причина изменения
Представьте, что вы открываете файл компонента, написанного кем-то другим, и видите объявления свойств и событий в виде простого текста. Сразу вам будет понятен интерфейс этого компонента, то есть что он хочет отправлять и получать.
В дополнение к предоставлению самодокументируемого кода вы также можете использовать объявления событий для проверки полезной нагрузки событий, хотя я не могу найти причину для этого в этом примере.
понять больше:Emits Option RFC
стиль содержимого слота
Чтобы сделать модальное окно многоразовым, мы предоставляем слот содержимого. Начнем с добавленияstyle
теги для оформления содержимого.
использовать в нашем компонентеscoped
CSS — это хорошая практика, позволяющая гарантировать, что правила, которые мы предоставляем, не окажут непреднамеренного воздействия на другое содержимое страницы.
Давайте выделять курсивом любой текст абзаца, который помещается в слот. Для этого мы будем использоватьp
Селектор создает новое правило CSS.
src/Modal.vue
<template>...</template>
<script>...</script>
<style scoped>
p {
font-style: italic;
}
</style>
Если вы попробуете, то обнаружите, что это не работает. Проблема в том, что стиль Scoped определяется во время компиляции, когда содержимое слота все еще принадлежит родительскому объекту.
Решение, предоставляемое Vue 3, заключается в предоставлении псевдоселектора::v-slotted()
, который позволяет нацеливаться на содержимое слотов с помощью правил области действия в компонентах, предоставляющих слоты.
Вот наше использование:
<style scoped>
::v-slotted(p) {
font-style: italic;
}
</style>
Vue 3 также включает некоторые другие новые селекторы Scoped Styling:::v-deep
а также::v-global
, вы можете узнать больше здесь:Scoped Styles RFC.
другие изменения
Вот и все новые функции, которые я могу описать на простом примере. В основном у меня есть основные из них, но вот некоторые, которые я считаю достаточно важными, чтобы изучить их самостоятельно, прежде чем подводить итоги статьи.
Дополнительный:
удаленный:
- Filters
- Inline templates
- Event interface for components(больше нет автобуса событий)
фиксированный:
В Vue Router также есть различные изменения, но я посвящу этим изменениям отдельный пост!
Данная статья была впервые опубликована на паблике "Front-End Full-Stack Developer".После того, как обратили внимание, просьба ответить личным сообщением: Большой подарочный пакет, отправка по сети качественных видеокурсов, информация о диске онлайн, обязательно сэкономить много денег!