Как быстро начать работу с vue 3.x

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

предисловие

В этой статье рассказывается об изменениях в использовании vue 3.x, а не о различиях в реализации кода.

Хотя реализация vue2 в vue3 претерпела серьезные изменения, использование изменилось мало.Одним из наиболее очевидных изменений является добавление функции setup(){}, и почти все конфигурации стали определяться как функции. Несмотря на это, есть много мелких изменений. В этой статье в основном рассказывается о некоторых общих различиях в использовании между vue 2.x и vue 3.x. Хотя не так много записано, это не так много. Источник этой статьи:GitHub.com/vUEJS/RFCs/…

Конечно, по умолчанию вы освоили использование vue 2.x, давайте посмотрим.

новый

composition-api

1. Повторное использование логики и организация кода

Это основное изменение в vue 3.0. Помимо изменения способа определения состояния, он также дает нам лучший опыт повторного использования логики и организации кода.Новый способ позволяет поместить тот же код бизнес-логики (состояние, вычисляемые свойства, методы и т. д.) в кусочек. Это может показаться немного расплывчатым, но если вы писали более сложные компоненты, вы обнаружите, что это хорошо. Функции-хуки created и beforeCreated из старой версии устарели и заменены настройкой в ​​vue 3.0.

2. Улучшенный вывод типов

Лучшая поддержка TypeScript.

Смотрите эту статью:GitHub.com/vUEJS/RFCs/…

Или прочтите это (на китайском):vue-composition-api-rfc.netlify.app/zh/

Полный API:vue-composition-api-rfc.netlify.app/zh/api.html

компонент телепорта

Компонент телепорта просто переносит содержимое, определенное внутри него, в целевой элемент, не создавая избыточных элементов в структуре элемента, и, конечно, это не повлияет на дерево компонентов, это эквивалентно прозрачному существованию. Зачем этот компонент? Для того, чтобы иметь лучший опыт организации кода. Например: иногда часть шаблона компонента логически принадлежит этому компоненту, но с технической точки зрения (например, требования к стилю) лучше переместить эту часть шаблона в другое место в DOM.

Например, модальные окна, диалоговые окна, уведомления, раскрывающиеся меню и т. д. некоторых библиотек компонентов пользовательского интерфейса должны управлять иерархическими отношениями через z-index.Если они находятся только на разных уровнях компонентов или элементов, то иерархический порядок z-index сложно гарантировать. Может быть, вы скажете, что многие UI-библиотеки еще не реализованы подобным образом? Что касается того, как реализована эта библиотека пользовательского интерфейса, я думаю, она должна напрямую манипулировать DOM. Зачем вообще предоставлять этот компонент телепорта? Это может быть из-за миссии самого Vue: постарайтесь не позволять разработчикам напрямую манипулировать DOM, все это делает Vue. Разработчики могут уделять больше времени развитию бизнеса.

<teleport to="#modals">
  <div>A</div>
</teleport>
<teleport to="#modals">
  <div>B</div>
</teleport>

<!-- result-->
<div id="modals">
  <div>A</div>
  <div>B</div>
</div>

Подробнее см.:GitHub.com/vUEJS/RFCs/…

Suspense

Загрузите асинхронные компоненты, неизвестность будет отображаться до загрузки асинковых компонентов и полностью отображенных#fallbackСодержимое слота.

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

#fallbackна самом деле это плагинv-soltсокращение для , в то время как первыйtemplateЕсли не указано, это слот по умолчанию.

изменять

синтаксис слота

GitHub.com/vUEJS/RFCs/…

Применимая версия: Версия: 2.x, Версия: 3.x

В будущих версиях vue можно сказать, что они объединены в один (slot и slot-scope).

<!-- vue 2.x -->
<foo>
  <bar slot="one" slot-scope="one">
    <div slot-scope="bar">
      {{ one }} {{ bar }}
    </div>
  </bar>

  <bar slot="two" slot-scope="two">
    <div slot-scope="bar">
      {{ two }} {{ bar }}
    </div>
  </bar>
</foo>

<!-- vue 3.x -->
<foo>
  <template v-slot:one="one">
    <bar v-slot="bar">
      <div>{{ one }} {{ bar }}</div>
    </bar>
  </template>

  <template v-slot:two="two">
    <bar v-slot="bar">
      <div>{{ two }} {{ bar }}</div>
    </bar>
  </template>
</foo>

Я думаю, что это хорошо, это то, что не смущает людей немного.

стенография

<TestComponent>
  <template #one="{ name }">Hello {{ name }}</template>
</TestComponent>

Динамические параметры инструкции

Применимая версия: Версия: 2.x, Версия: 3.x

<!-- v-bind with dynamic key -->
<div v-bind:[key]="value"></div>

<!-- v-bind shorthand with dynamic key -->
<div :[key]="value"></div>

<!-- v-on with dynamic event -->
<div v-on:[event]="handler"></div>

<!-- v-on shorthand with dynamic event -->
<div @[event]="handler"></div>

<!-- v-slot with dynamic name -->
<foo>
  <template v-slot:[name]>
    Hello
  </template>
</foo>

<!-- v-slot shorthand with dynamic name -->
<!-- pending #3 -->
<foo>
  <template #[name]>
    Default slot
  </template>
</foo>

Проще говоря, имя команды, имя события и имя слота можно определить с помощью переменных.

Tree-shaking

Применимая версия: Версия: 3.x

В версии 3 все API не будут упакованы, будут упакованы только те API, которые вы используете.

<!-- vue 2.x -->
import Vue from 'vue'

Vue.nextTick(() => {})

const obj = Vue.observable({})

<!-- vue 3.x -->
import Vue, { nextTick, observable } from 'vue'

Vue.nextTick // undefined

nextTick(() => {})

const obj = observable({})

То есть то, что мы используем в проекте, будет только упаковано, а не все API будут упакованы, как vue 2.x.

.sync имеет большое значение

Применимая версия: vue 3.x

<!-- vue 2.x -->
<MyComponent v-bind:title.sync="title" />

<!-- vue 3.x -->
<MyComponent v-model:title="title" />

То есть vue 3.0 удалил .sync и объединил его с v-model, а внутренняя реализация v-model также была немного скорректирована.

элемент

<input v-model="xxx">

<!-- would be shorthand for: -->

<input
  :model-value="xxx"
  @update:model-value="newValue => { xxx = newValue }"
>

компоненты

<MyComponent v-model:aaa="xxx"/>

<!-- would be shorthand for: -->

<MyComponent
  :aaa="xxx"
  @update:aaa="newValue => { xxx = newValue }"
/>

Однако похоже, что альфа-версия группы пока не поддерживается.v-model:aaa="xxx"

функциональный компонент

Применимая версия: vue 3.x

<!-- vue 2.x -->
const FunctionalComp = {
  functional: true,
  render(h) {
    return h('div', `Hello! ${props.name}`)
  }
}
    
<!-- vue 3.x -->
import { h } from 'vue'
const FunctionalComp = (props, { slots, attrs, emit }) => {
  return h('div', `Hello! ${props.name}`)
}

Больше не нуженfunctional:trueопции,<template functional>больше не платить

Асинхронные компоненты также должны быть созданы с помощью метода API.

import { defineAsyncComponent } from 'vue'
const AsyncComp = defineAsyncComponent(() => import('./Foo.vue'))

глобальный API

Применимая версия: vue 3.x

в версии 2.x

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

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

Vue.prototype.customProperty = () => {}

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

в vue 3.x

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

const app = createApp(App)

app.config.isCustomElement = tag => tag.startsWith('app-')
app.use(/* ... */)
app.mixin(/* ... */)
app.component(/* ... */)
app.directive(/* ... */)

app.config.globalProperties.customProperty = () => {}

app.mount(App, '#app')

Как видите, способ создания экземпляров также изменился. Некоторые глобальные методы API находятся не в глобале, а в экземпляре.

Больше изменений можно найти здесь:GitHub.com/vUEJS/RFCs/…

v-model

Применимая версия: Версия 3.x

1. Сохранен оригинальный способ

<input v-model="foo">

2. Можно связать несколько v-моделей

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

По сути, вышеописанный метод эквивалентен предыдущему .sync .

3. Дополнительная обработка

<Comp
   v-model:foo.trim="text"
   v-model:bar.number="number" />

Мы можем добавить дополнительную обработку к этому свойству

Функция крюка для обучения

Применимая версия: Версия 3.x

В vue 3.x функция ловушки директивы следует правилам именования функции ловушки в компоненте

2.x

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

В версии 3.0

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

transition

Применимая версия: Версия 3.x

когда<transition>Внешний переключатель не запускает эффект перехода, если он является корневым элементом компонента.

vue 2.x

<!-- modal component -->
<template>
  <transition>
    <div class="modal"><slot/></div>
  </transition>
</template>

<!-- usage -->
<modal v-if="showModal">hello</modal>

vue 3.x

<!-- modal component -->
<template>
  <transition>
    <div v-if="show" class="modal"><slot/></div>
  </transition>
</template>

<!-- usage -->
<modal :show="showModal">hello</modal>

То есть мы можем только<transition>Используйте переключатель внутри.

transition-class

Переименуйте два класса перехода

v-enterпереименован вv-enter-from,v-leaveпереименован вv-enter-from.

.v-enter-from, .v-leave-to {
  opacity: 0;
}
.v-leave-from, .v-enter-to {
  opacity: 1
}

Router

Подходящая версия: Версия: Vue (2.x/3.x) Vue Router (3.x/4.x)

изменения маршрутизатора

router-linkДобавить кscoped-slotAPI и пользовательские свойства, а также удаленные свойства тегов и событий.

Добавить кscoped-slotкакая функция? Если раньше мы могли менять стиль элементов только через активный класс, то теперь с помощью Scoped-Slot мы более гибкие и можемscoped-slotВозвращаемое состояние настраивается, будь то стиль или класс.

<router-link to="/" custom v-slot="{ href, navigate, isActive }">
  <li :class="{ 'active': isActive }">
    <a :href="href" @click="navigate">
      <Icon>home</Icon><span class="xs-hidden">Home</span>
    </a>
  </li>
</router-link>

То есть новая версия Router более чистая, предоставляет нам только некоторые параметры, давайте использовать эти параметры для реализации различных сценариев.

мета слияние

{
  path: '/parent',
  meta: { requiresAuth: true, isChild: false },
  children: [
    { path: 'child', meta: { isChild: true }}
  ]
}

при посещении/parent/child, мета в подмаршруте выглядит следующим образом:

{ requiresAuth: true, isChild: true }

Слияние стратегии иObject.assignаналогичный

Маршрут соответствует всем

const routes = [
  {
    path: '/',
    name: 'Home',
    component: () => import(/* webpackChunkName: "Home" */ '../views/Home.vue')
  },
  {
    path: '/about',
    name: 'About',
    component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
  },
  {
    path: '/:catchAll(.*)',
    name: 'All',
    component: () => import(/* webpackChunkName: "All" */ '../views/Home.vue')
  }
]

Вот этот Vue-router соответствует всем роутингам, он изменился, не старая версия*, в новой версии, пожалуйста, обратитесь к приведенному выше примеру кода

Получить текущую информацию о маршрутизации

import router from '../router'
export default {
  setup () {
    const currentRoute = router.currentRoute.value
    console.log(currentRoute)
  }
}

Представленный роутер пропускает нас черезcreateRouter()метод создал объект

import { createRouter, createWebHashHistory } from 'vue-router'
const router = createRouter({
  history: createWebHashHistory(),
  routes
})

routesМаршруты — это массив определенных нами маршрутов, как и в старой версии.

стиль ограничен

Применимая версия: Версия: 2.x, 3.x

написание старой версии

/* 深度选择器 */
/*方式一:*/
>>> .foo{ }
/*方式二:*/
/deep/ .foo{ }
/*方式三*/
::v-deep .foo{ }

написание новой версии

/* 深度选择器 */
::v-deep(.foo) {}

Кроме селектора глубины выше, есть еще два, которые написаны точно так же.

/* slot content 起作用 */
::v-slotted(.foo) {}

/* 全局 */
::v-global(.foo) {}

корректировка стоимости недвижимости

Применимая версия: Версия: 3.x

Vue сам будет соответствующим образом обрабатывать атрибуты элемента. В более старых версиях vue это обрабатывалось следующим образом:

выражение обычный окончательно переработаны в
:attr="null" / draggable="false"
:attr="undefined" / /
:attr="true" foo="true" draggable="true"
:attr="false" / draggable="false"
:attr="0" foo="0" draggable="true"
attr="" foo="" draggable="true"
attr="foo" foo="foo" draggable="true"
attr foo="" draggable="true"

Как обращаться с новой версией:

выражение обычный окончательно переработаны в
:attr="null" / /
:attr="undefined" / /
:attr="true" foo="true" draggable="true"
:attr="false" foo="false" draggable="false"
:attr="0" foo="0" draggable="0"
attr="" foo="" draggable=""
attr="foo" foo="foo" draggable="foo"
attr foo="" draggable=""

В новой версии в основном остается как есть, то есть какое значение атрибута мы добавляем к элементу, и какое значение атрибута лучше всего использовать после обработки vue.

Асинхронные компоненты

import { defineAsyncComponent } from "vue"

// simple usage
const AsyncFoo = defineAsyncComponent(() => import("./Foo.vue"))

Орфография несколько отличается от предыдущей.

динамическая маршрутизация

Применимая версия Router 4

Добавлено несколько методов

  1. router.addRoute(route: RouteRecord)Динамически добавлять маршруты
  2. router.removeRoute(name: string | symbol), динамически удалять маршруты
  3. router.hasRoute(name: string | symbol): boolean, чтобы определить, существует ли маршрут
  4. router.getRoutes(): RouteRecord[]Получить список маршрутов
router.addRoute({
  path: '/new-route',
  name: 'NewRoute',
  component: NewRoute
})

// add to the children of an existing route
router.addRoute('ParentRoute', {
  path: 'new-route',
  name: 'NewRoute',
  component: NewRoute
})

router.removeRoute('NewRoute')

// normalized version of the records added
const routeRecords = router.getRoutes()

Подробности можно найти по адресу:GitHub.com/vUEJS/RFCs/…

emits-option

const Foo = defineComponent({
  emits: {
    submit: (payload: { email: string; password: string }) => {
      // perform runtime validation
    }
  },

  methods: {
    onSubmit() {
      this.$emit('submit', {
        email: 'foo@bar.com',
        password: 123 // Type error!
      })

      this.$emit('non-declared-event') // Type error!
    }
  }
})

настоящее время$emit()Использование метода не изменилось, но необходимо дополнительно определить объект emits, но следует отметить, что альфа-версия пока не поддерживает TypeScript.

Количество корневых элементов компонента

После vue 3 компонент больше не ограничивает количество корневых элементов в шаблоне (в старой версии был только один корневой элемент).

vue 3.x освобожден от средней платы

  • перед созданием, созданный
  • filters
  • keycode
  • inline-template
  • data-object
  • on,выкл и $один раз

После прочтения этой статьи я полагаю, что у вас, вероятно, есть общее представление о vue 3. Хотя эта статья не позволит вам мгновенно стать драйвером vue 3.x, она позволит вам неявно испытать новые функции vue 3.x. В частности, API композиции, хоть он и не описан подробно в этой статье, все о нем можно прочитать по дополнительным ссылкам. Я думаю, API композиции действительно крутой.

vue план

GitHub.com/v UE JS/v UE/боюсь…