Захватывающие новые функции в Vue 3

внешний интерфейс Vue.js

Филип Раковски

Перевод: сумасшедший технический ботаник

оригинал:v UE school.IO/articles/vu…

Копирование без разрешения строго запрещено

В предыдущей статье мыУзнайте об улучшениях производительности, которые принесет Vue 3. Мы уже знаем, что программы, написанные на новом Vue 3, будут работать хорошо, но производительность — не самая важная часть. Для разработчиков важнее всего то, как новая версия повлияет на то, как мы пишем код.

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

Начнем с API, о котором многие из вас наверняка слышали... Давайте начнем с API, о котором многие из вас, вероятно, слышали...

API композиции

Компонентный API — это наиболее часто обсуждаемый и рекомендуемый синтаксис в следующей основной версии Vue. Это совершенно новый подход к повторному использованию логики и организации кода.

В настоящее время мы создаем наши компоненты, используя так называемый Options API. Чтобы добавить логику к компоненту Vue, мы заполняем (необязательные) свойства, такие какdata,methods,computedЖдать. Самым большим недостатком этого подхода является то, что он сам по себе не является допустимым кодом JavaScript. Вам необходимо точно знать, какие свойства доступны в шаблоне иthisПоведение ключевых слов. За кулисами компилятору Vue необходимо преобразовать это свойство в рабочий код. Таким образом, мы не можем извлечь выгоду из самовнушения или проверки типов.

API компонентов призван решить эту проблему, предоставляя механизмы, доступные в настоящее время в свойствах компонентов, в виде функций JavaScript. Основная команда Vue описывает API компонента как«Набор дополнительных API-интерфейсов на основе функций для гибкой композиции логики компонентов».Код, написанный с помощью компонентного API, более удобочитаем и не содержит магии, что облегчает его чтение и изучение.

Давайте посмотрим, как это работает, на простом примере компонента, использующего новый API компонента.

<template>
  <button @click="increment">
    Count is: {{ count }}, double is {{ double }}, click to increment.
  </button>
</template>

<script>
import { ref, computed, onMounted } from 'vue'

export default {
  setup() {
    const count = ref(0)
    const double = computed(() => count.value * 2)

    function increment() {
      count.value++
    }

    onMounted(() => console.log('component mounted!'))

    return {
      count,
      double,
      increment
    }
  }
}
</script>

Теперь давайте разобьем код на части, чтобы понять, что происходит:

import { ref, computed, onMounted } from 'vue'

Как я упоминал ранее, API компонентов предоставляет свойства компонентов в виде функций, поэтому первым шагом является импорт необходимых функций. В примере нужно использоватьrefСоздайте адаптивную ссылку сcomputedСоздайте вычисляемое свойство и используйтеonMountedДоступ к установленным хукам жизненного цикла.

Теперь вам может быть интересно узнать об этом таинственномsetupЧто именно представляет собой метод?

export default {
  setup() {

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

мы неsetupСодержимое, возвращаемое функцией, не будет доступно в шаблоне.

const count = ref(0)

Из вышеизложенного заявляем, что сrefимя функцииcountСвойство ответа. Он может обернуть любой примитив или объект и вернуть его реактивную ссылку. Значение переданного элемента будет сохранено в созданной ссылкеvalueв свойствах. Например, если вы хотите получить доступcountссылочное значение, вам нужно явно запросить егоcount.value.

const double = computed(() => count.value * 2)

function increment() {
  count.value++
}

Это то, что мы вычисляем свойства в заявленииdoubleа такжеincrementфункция делать.

onMounted(() => console.log('component mounted!'))

использоватьonMountedhook, мы запишем несколько сообщений, когда компонент будет установлен, просто чтобы показать вам, что это можно сделать! 😉

return {
  count,
  double,
  increment
}

Наконец, мы будем использоватьincrementметод возвращаетcountа такжеdoubleсвойства, чтобы сделать их доступными в шаблоне.

<template>
  <button @click="increment">
    Count is: {{ count }}, double is {{ double }}. Click to increment.
  </button>
</template>

Вуаля! Теперь мы можем получить доступ к шаблону вsetupМетоды возвращают свойства и функции, как если бы они были объявлены через старый API параметров.

Это простой пример, который также можно легко реализовать с помощью API параметров. Реальные преимущества нового компонентного API заключаются не только в возможности кодировать по-другому, эти преимущества также проявляются при повторном использовании нашего кода и логики.

Повторное использование кода с компонентным API

Новый API компонентов имеет больше преимуществ. Подумайте о повторном использовании кода. В настоящее время, если мы хотим поделиться некоторым кодом между другими компонентами, доступны два варианта: миксины и слоты с ограниченной областью действия. Но у обоих есть недостатки.

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

Начнем с миксинов:

import CounterMixin from './mixins/counter'

export default {
  mixins: [CounterMixin]
}

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

Вот слоты с ограниченной областью действия:

<template>
  <Counter v-slot="{ count, increment }">
     {{ count }}
    <button @click="increment">Increment</button> 
  </Counter> 
</template>

Используя слоты с областью видимости, мы точно знаем, что можем передатьv-slotК каким свойствам обращаются свойства, поэтому код легче понять. Недостатком этого подхода является то, что мы можем получить к нему доступ только в шаблоне и только вCounterИспользуется в области компонента.

Теперь пришло время использовать API компонента:

function useCounter() {
  const count = ref(0)
  function increment () { count.value++ }

  return {
    count,
    incrememt
  }
}

export default {
  setup () {
    const { count, increment } = useCounter()
    return {
      count,
      increment
    }
  }
}

Это более элегантно? Мы не ограничены рамками шаблона и компонента и точно знаем, к каким свойствам можно получить доступ из counter. Кроме того, мы можем извлечь выгоду из функции завершения кода, доступной в редакторе, потому чтоuseCounterПросто функция, которая возвращает некоторые свойства, поэтому редактор может помочь нам с проверкой типов и предложениями.

Это также более элегантный способ использования сторонних библиотек. Например, если бы мы хотели использовать Vuex, мы могли бы явно использоватьuseStoreвместо того, чтобы загрязнять прототип Vue (this.$store). Этот подход также устраняет закулисную магию плагинов Vue.

const { commit, dispatch } = useStore()

Если вы хотите узнать больше об Component API и вариантах его использования, я настоятельно рекомендую вам прочитать команду Vue.эта статья, который объясняет причины нового API и предлагает наилучшие варианты использования. а такжеgreat repository, который содержит пример API компонентов, используемый Торстеном Люнборгом из основной команды Vue.

Глобальные изменения API монтирования/настройки

Мы можем найти еще одно важное изменение в способе создания и настройки программ. Давайте посмотрим, как это работает сейчас:

import Vue from 'vue'
import App from './App.vue'

Vue.config.ignoredElements = [/^app-/]
Vue.use(/* ... */)
Vue.mixin(/* ... */)
Vue.component(/* ... */)
Vue.directive(/* ... */)

new Vue({
  render: h => h(App)
}).$mount('#app')

В настоящее время мы используем глобальнуюVueОбъект предоставляет всю конфигурацию и создает новый экземпляр Vue. правильноVueЛюбые изменения, внесенные в объект, повлияют на каждый экземпляр и компонент Vue.

Теперь давайте посмотрим, как это работает в Vue 3:

import { createApp } from 'vue'
import App from './App.vue'

const app = createApp(App)

app.config.ignoredElements = [/^app-/]
app.use(/* ... */)
app.mixin(/* ... */)
app.component(/* ... */)
app.directive(/* ... */)

app.mount('#app')

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

Это может упростить ваш код проще понять, а менее склонны к неожиданным проблемам, вызванным сторонним плагинами. В настоящее время, если некоторые сторонние решения изменяют Vue объекты, то он может быть неожиданным способами (особенно глобальным смесью) влияет на вашу программу, и Vue 3 не является проблемой.

В настоящее время эти изменения APIэтот RFCобсуждается, а это значит, что это может измениться в будущем.

Фрагменты

Еще одно интересное дополнение, которое мы можем ожидать в Vue 3, — это фрагменты.

Какой фрагмент вы могли бы спросить? Что ж, если вы создаете компонент Vue, у него может быть только один корневой узел.

Это означает, что такой компонент не может быть создан:

<template>
  <div>Hello</div>
  <div>World</div>
</template>

Причина в том, что экземпляр VUE, представляющий любой вариант VUE, должен быть связан в один элемент DOM. Единственный способ создания компонента с несколькими узлами DOM состоит в том, чтобы создать функциональный компонент без основного экземпляра Vue.

Оказывается, у сообщества React такая же проблема. Решением, которое они придумали, был фиктивный элемент под названием Fragment. выглядит так;

class Columns extends React.Component {
  render() {
    return (
      <React.Fragment>
        <td>Hello</td>
        <td>World</td>
      </React.Fragment>
    );
  }
}

Хотя фрагмент выглядит как обычный элемент DOM, он виртуальный и вообще не отображается в дереве DOM. Это позволяет нам связать функциональность компонента с одним элементом, не создавая избыточных узлов DOM.

Теперь вы можете использоватьvue-fragmentsФрагменты используются в Vue 2 библиотеки, а в Vue 3 вы можете использовать ее напрямую!

Suspense

Еще одна функция, извлеченная из React, которая будет использоваться в Vue 3, — это компоненты Suspense.

Приостановка может приостановить рендеринг вашего компонента и рендеринг вспомогательных компонентов до тех пор, пока не будет выполнено условие. Во время Vue London Юкси Ю кратко затронул эту тему и показал нам, каких API ожидать. Получается, что Suspense — это просто компонент со слотом:

<Suspense>
  <template >
    <Suspended-component />
  </template>
  <template #fallback>
    Loading...
  </template>
</Suspense>

доSuspended-componentРезервный контент будет показан до полного рендеринга. Приостановка может дождаться загрузки компонента (если компонент асинхронный) илиsetupФункция для выполнения некоторой асинхронной операции.

Multiple v-models

V-модель — это директива, которую можно использовать для реализации двусторонней привязки к данному компоненту. Мы можем передавать реактивные свойства и изменять их внутри компонента.

Мы можем получить хорошее представление об элементах формыv-model:

<input v-bind="property />

Но вы знаете, что можете использовать его для каждого компонентаv-model? Внутренний,v-modelпросто пройтиvalueсвойства и прослушиваниеinputЯрлыки к событиям. Переписав приведенный выше пример в следующий синтаксис, вы получите точно такой же эффект:

<input 
  v-bind:value="property"
  v-on:input="property = $event.target.value"
/>

Мы даже можем использовать компонентыmodelproperties, чтобы изменить имена свойств и событий по умолчанию:

model: {
  prop: 'checked',
  event: 'change'
}

Как видите, если мы хотим сделать ставки на двусторонние привязки в компоненте,v-modelИнструкции могут быть очень полезным синтаксисом. К сожалению, каждый компонент может иметь только одинv-model.

К счастью, в Vue 3 это не будет проблемой! ты сможешь датьv-modelимена свойств и иметь столько имен свойств, сколько вы хотите. В приведенном ниже примере вы можете найти два компонента формыv-model:

<InviteeForm
  v-model:name="inviteeName"
  v-model:email="inviteeEmail"
/>

Изменения в этом API в настоящее времяэтот RFCобсуждение, а это значит, что в будущем могут быть изменения.

Portals

Порталы — это специальные компоненты, используемые для рендеринга чего-либо вне текущего компонента. это такжеРеализовано в Реактодна из функций. Вот что говорится в документации React о порталах:

"Порталы предоставляют уникальный способ визуализации дочерних элементов в узлах DOM за пределами иерархии DOM родительского компонента."

Этот режим обработки является очень хорошим методом, используемым для всплывающих окон и компонентов, которые обычно отображаются в верхней части страницы. Используя порталы, вы можете гарантировать, что никакие правила CSS компонентов хоста не повлияют на компоненты, которые вы хотите отобразить, и вы можете избежать использованияz-indexПроизведена хакерская атака.

Для каждого портала нам нужно указать целевое местоположение, в котором будет отображаться содержимое портала. Ниже вы можете получить отportal-vueПосмотрите реализацию в библиотеке, которая добавляет этот функционал в Vue 2:

<portal to="destination">
  <p>This slot content will be rendered wherever thportal-target with name 'destination'
    is  located.</p>
</portal>

<portal-target name="destination">
  <!--
  This component can be located anywhere in your App.
  The slot content of the above portal component wilbe rendered here.
  -->
</portal-target>

Vue 3 имеет встроенную поддержку порталов!

Новый API пользовательских директив

Пользовательский API директив будет немного изменен в Vue 3, чтобы лучше соответствовать жизненному циклу компонента. Это улучшение должно сделать API более интуитивно понятным, чтобы новичкам было легче понять и изучить API.

Это текущий API пользовательских директив:

const MyDirective = {
  bind(el, binding, vnode, prevVnode) {},
  inserted() {},
  update() {},
  componentUpdated() {},
  unbind() {}
}

Вот как это выглядит в Vue 3.

const MyDirective = {
  beforeMount(el, binding, vnode, prevVnode) {},
  mounted() {},
  beforeUpdate() {},
  updated() {},
  beforeUnmount() {}, // new
  unmounted() {}
}

Даже если это серьезное улучшение, оно должно быть легко реализовано в версии, совместимой с Vue.

в этом RFCИзменения в этом API обсуждаются в , что означает, что он может быть улучшен в будущем.

Резюме

В дополнение к Composition API, который является самым крупным новым API в Vue 3, мы можем найти множество небольших улучшений. Видно, что Vue движется к более удобному опыту разработки и более простому и интуитивно понятному API. Приятно видеть, что команда Vue решила использовать многие идеи в основе фреймворка, которые в настоящее время доступны только через сторонние библиотеки.

В приведенном выше списке представлены только основные изменения и улучшения API. Если вам интересен другой контент, обязательно проверьтеРепозиторий Vue RFC.

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