Учебник по Vue 3 (для пользователей Vue 2)

JavaScript Vue.js
Учебник по Vue 3 (для пользователей Vue 2)

Vue 3 официально не выпущен, но сопровождающий выпустил бета-версию, чтобы наши участники могли попробовать и оставить отзыв.

Если вам интересно, каковы основные функции и основные изменения в Vue 3, то я сосредоточусь на них в этом посте, предлагая вам создать простое приложение с помощью Vue 3 beta 9.

Я расскажу как можно больше нового, включая фрагменты, телепорты, Composition API и некоторые другие малоизвестные изменения. Я попытаюсь объяснить причину этой функции или изменения.


Статьи по теме 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теги для оформления содержимого.

использовать в нашем компонентеscopedCSS — это хорошая практика, позволяющая гарантировать, что правила, которые мы предоставляем, не окажут непреднамеренного воздействия на другое содержимое страницы.

Давайте выделять курсивом любой текст абзаца, который помещается в слот. Для этого мы будем использовать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.

другие изменения

Вот и все новые функции, которые я могу описать на простом примере. В основном у меня есть основные из них, но вот некоторые, которые я считаю достаточно важными, чтобы изучить их самостоятельно, прежде чем подводить итоги статьи.

Дополнительный:

удаленный:

фиксированный:

В Vue Router также есть различные изменения, но я посвящу этим изменениям отдельный пост!


Данная статья была впервые опубликована на паблике "Front-End Full-Stack Developer".После того, как обратили внимание, просьба ответить личным сообщением: Большой подарочный пакет, отправка по сети качественных видеокурсов, информация о диске онлайн, обязательно сэкономить много денег!