предисловие
В этой статье рассказывается об изменениях в использовании 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
Если не указано, это слот по умолчанию.
изменять
синтаксис слота
Применимая версия: Версия: 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-slot
API и пользовательские свойства, а также удаленные свойства тегов и событий.
Добавить к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
Добавлено несколько методов
-
router.addRoute(route: RouteRecord)
Динамически добавлять маршруты -
router.removeRoute(name: string | symbol)
, динамически удалять маршруты -
router.hasRoute(name: string | symbol): boolean
, чтобы определить, существует ли маршрут -
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
- выкл и $один раз
После прочтения этой статьи я полагаю, что у вас, вероятно, есть общее представление о vue 3. Хотя эта статья не позволит вам мгновенно стать драйвером vue 3.x, она позволит вам неявно испытать новые функции vue 3.x. В частности, API композиции, хоть он и не описан подробно в этой статье, все о нем можно прочитать по дополнительным ссылкам. Я думаю, API композиции действительно крутой.