Йода объявилVue3.0вошелКандидатский этап【Поздравляем】! ! ! Также возможно продвижениепроверять, который инициализирует проект напрямую через Vite.Vue3.0Бета-версия документации также была запущена, и заинтересованные друзья могут заглянуть внутрь. Кроме тогопоказать путь➡️ Часть руководства по API для Vue3, выпущенного ранее, которое включает в себя сложный и сложный системный API с реагированием и составной API.
Обзор
Новые функции Vue3.0
-
Composition API---- API композиции, включая
setup()Ждать -
Reactivity API---- API реактивной системы, в том числе
ref()Ждать - Teleport--- Встроенный компонент доставки
-
Fragments---
templateВ Vue2.x может быть несколько корневых DOM (или компонентов), но может существовать только один - EmitsДобавлен настраиваемый параметр события в компонент
-
v-modelМодификацию , вы можете передать в параметрах, так что вы можете использовать несколькоv-model, так же можно настроить модификаторы, удалены.syncмодификатор. createRendererAPI from@vue/runtime-coreto create custom renderers
удаленный контент
- удаленный
keyCodeмодификатор, вы можете использоватьkebab-caseимя вместо этого (например,.delete/.enter) - удалил экземпляр
$on,$offа также$onceметод - удаленныйфильтр
Filters, Vue3.0 рекомендуется использоватьcomputedреализовать - удаленныйInline templates attributes
- удаленный
.syncмодификатор
Справочник по API / Новые и устаревшие API
---【Жирный курсив означает новые добавления, зачеркнутый шрифт означает удаление, а курсив означает изменения.]---
API экземпляров (отдельно от глобального API)
В Vue 3 API, который глобально изменил поведение Vue, был перемещен в экземпляр (черезcreateAppсоздан) в API. Они влияют только на этот экземпляр.
следующим образом:mount,provide,unmount,directive(Хук жизненного цикла пользовательской инструкции был переименован),component,config,mixin,use
Глобальный API
createApp,h(render()псевдоним),defineComponent,defineAsyncComponent,resolveComponent(может использоваться только в функциях рендеринга),resolveDirective(может использоваться только в функциях рендеринга),withDirectives(может использоваться только в функциях рендеринга),createRenderer(может использоваться только в функциях рендеринга),nextTick,,extend,filter,compile(лоскутное одеялоobservablereactiveальтернатива),,versionset
Опции
Data
emits,data,props,computed,methods,watch,propsData
DOM
template,render,,elrenderError
крючки жизненного цикла
beforeCreate,created,beforeMount,mounted,beforeUpdate,updated,activated,deactivated,beforeUnmount(),beforeDestroyunmounted(),destroyederrorCaptured,renderTracked,renderTriggered
ресурс
directives,components,filters
комбинация
mixins,extends,provide / inject,setup,parent
разное
name,inheritAttrs,,delimiters,functional,modelcomments
свойства экземпляра
$data,$props,$el,$options,$parent,$root,$slots,$refs,$attrs,,$children,$scopedSlots,$isServer$listeners
Методы экземпляра (здесь также объединены жизненные циклы)
$watch,$emit,$forceUpdate,$nextTick,(обратите внимание, что это недоступно),$set,$delete,$mountdestroy
инструкция
v-text,v-html,v-show,v-if,v-else,v-else-if,v-for,v-on,v-bind,v-model,v-slot,v-pre,v-cloak,v-once,v-is(Первоначально черезisвыполнить)
специальные свойства
key,ref,is,,slot,slot-scope(Эти 3 устарели в Vue 2.6 и выше)scope
встроенные компоненты
component,transition,transition-group,keep-alive,slot,teleport
[Новое] API адаптивной системы (API реактивности)
Основные реактивные API
reactive,readonly,isProxy,isReactive,isReadonly,toRaw,markRaw,shallowReactive,shallowReadonly
refs
ref,unref,toRef,toRefs,isRef,customRef,shallowRef
Computed and watch
computed,watchEffect,watch
[Новое] API композиции (API композиции)
setup,onBeforeMount,onMounted,onBeforeUpdate,onUpdated,onBeforeUnmount,onUnmounted,onErrorCaptured,onRenderTracked,onRenderTriggered,provide,inject
Вот мое сравнениеVue2.xНекоторые различия в учебной части документа версии приветствуются для дополнения или предоставления предложений по модификации (поскольку китайская версия еще не найдена, так что это просто мое собственное понимание, ссылка на эту часть документа была вставлена в точке знаний вы можете просмотреть исходный текст напрямую).
Основное использование
Как создать экземпляр Vue:
существуетVue2.xв, черезnew VueСоздайте экземпляр Vue и передайтеэль параметрсмонтировать DOM
<!-- Vue2.x 创建实例 -->
var vm = new Vue({
// 选项
})
<!-- Vue2.x 挂载DOM -->
var vm = new Vue({
el: '#app',
data: {a:1}
})
существуетVue3.0в, черезcreateAppметод для создания экземпляра Vue. После создания экземпляра вы можете передать контейнер вmountспособ крепления
<!-- Vue3.0 创建实例 -->
Vue.createApp(/* options */)
<!-- Vue3.0 挂载DOM -->
Vue.createApp(/* options */).mount('#app')
Жизненный цикл
Жизненный цикл не сильно изменился, есть некоторые тонкие различия, связанные с изменением способа создания экземпляра.
Стоит отметить, что: вVue2.x, два хука для уничтожения экземпляраbeforeDestoryтак же какdestoryed, пока вVue3.0Измените имена этих двух хуков наbeforeUnmountа такжеunmounted.
Жизненный цикл Vue2.x
Жизненный цикл Vue3.0
Provide / inject
В Vue3.0 добавлена поддержка руководств.Provide / injectизописывать
динамические компоненты
Vue2.x и Vue3.0 по-прежнему применяются путем добавления специального элемента во Vue.isсвойства для реализации
<!-- 组件会在 `currentTabComponent` 改变时改变 -->
<component v-bind:is="currentTabComponent"></component>
Но для анализа шаблонов DOM, таких как<ul>,<table>и т. д. ограничивают частный случай внутренних элементов по сравнению сVue2.xв привязкеisАтрибуты,Vue3.0при условии,v-isинструкция
<!-- Vue2.x 使用 is 属性 -->
<table>
<tr is="blog-post-row"></tr>
</table>
<!-- Vue3.0 使用 v-is 指令 -->
<table>
<tr v-is="'blog-post-row'"></tr>
</table>
пользовательское событие
Vue2.x и Vue3.0 все еще работают$emit('myEvent')триггерное событие,пройти черезv-on:myEventДля прослушивания событий разница в том, что Vue3.0 предоставляет в компонентеemitsсвойства для определения событий
<!-- Vue3.0 自定义事件 -->
app.component('custom-form', {
emits: ['in-focus', 'submit']
})
Вы даже можете добавить проверку к пользовательским событиям, и в этом случае вам нужно поставитьemitsУстановите объект и назначьте имя события функции, которая получает$emitаргументы для вызова и возвращает логическое значение, чтобы указать, действительно ли событие
<!-- Vue3.0 为自定义事件添加校验 -->
app.component('custom-form', {
emits: {
// No validation
click: null,
// Validate submit event
submit: ({ email, password }) => {
if (email && password) {
return true
} else {
console.warn('Invalid submit event payload!')
return false
}
}
},
methods: {
submitForm() {
this.$emit('submit', { email, password })
}
}
})
Пользовательские компонентыv-model
существуетVue2.xсередина,v-modelПо умолчанию он будет использоватьvalueв качестве имени реквизита иinputкак имя инициированного события. Для особых сценариев вы также можете передатьmodelвозможность указать имя реквизита и имя события (обратите внимание, что в настоящее время этот реквизит все еще необходимо объявить в реквизитах)
<!-- Vue2.0 自定义 v-model -->
Vue.component('base-checkbox', {
model: {
prop: 'checked',
event: 'change'
},
props: {
checked: Boolean
},
template: `
<input
type="checkbox"
v-bind:checked="checked"
v-on:change="$emit('change', $event.target.checked)"
>
`
})
осторожность,существуетVue3.0середина,v-modelПо умолчанию он будет использоватьmodelValueв качестве имени реквизита иupdate:modelValueкак имя инициированного события.
поддержка каждогоv-modelпроходить впараметр, так что вы можете использовать несколько v-моделей на одном компоненте одновременно
<!-- Vue3.0 自定义 v-model 并且传入参数 -->
<my-component v-model:foo="bar" v-model:name="userName"></my-component>
можно даже установить для v-моделипользовательский модификатор, по умолчанию определяется в реквизитахmodelModifiersобъект для принятия модификаторов, поэтому вы можете использовать модификаторы для настройки различных механизмов запуска событий, которые вы хотите
<!-- Vue3.0 自定义修饰符默认接收方式 -->
<div id="app">
<my-component v-model.capitalize="myText"></my-component>
{{ myText }}
</div>
const app = Vue.createApp({
data() {
return {
myText: ''
}
}
})
app.component('my-component', {
props: {
modelValue: String,
modelModifiers: {
default: () => ({})
}
},
methods: {
emitValue(e) {
let value = e.target.value
if (this.modelModifiers.capitalize) {
value = value.charAt(0).toUpperCase() + value.slice(1)
}
this.$emit('update:modelValue', value)
}
},
template: `<input
type="text"
v-bind:value="modelValue"
v-on:input="emitValue">`
})
app.mount('#app')
Конечно, для переданного параметраv-model, вам нужно настроить его в реквизитахarg + "Modifiers"чтобы получить это параметризованноеv-modelмодификатор
<!-- Vue3.0 自定义参数的自定义修饰符 -->
<my-component v-model:foo.capitalize="bar"></my-component>
app.component('my-component', {
props: ['foo', 'fooModifiers'],
template: `
<input type="text"
v-bind:value="foo"
v-on:input="$emit('update:foo', $event.target.value)">
`,
created() {
console.log(this.fooModifiers) // { capitalize: true }
}
})
миксин
Vue2.x смешатьпуть черезVue.extend({mixins: [myMixin]})Определите компонент, который использует миксин
// 定义一个混入对象
var myMixin = {
created: function () {
this.hello()
},
methods: {
hello: function () {
console.log('hello from mixin!')
}
}
}
// 定义一个使用混入对象的组件
var Component = Vue.extend({
mixins: [myMixin]
})
var component = new Component() // => "hello from mixin!"
а такжеVue3.0похоже на создание экземпляра,Vue.createApp({mixins: [myMixin]})Определите компонент, который использует миксин
// 定义一个混入对象
const myMixin = {
created() {
this.hello()
},
methods: {
hello() {
console.log('hello from mixin!')
}
}
}
// 定义一个使用混入对象的组件
const app = Vue.createApp({
mixins: [myMixin]
})
app.mount('#mixins-basic') // => "hello from mixin!"
пользовательская директива
Vue2.xОбъект определения директивы содержит5крючки:
-
bind: Вызывается только один раз, когда директива впервые привязывается к элементу. Здесь можно выполнить одноразовые настройки инициализации. -
inserted: вызывается, когда связанный элемент вставляется в родительский узел (гарантируется существование только родительского узла, но не обязательно вставленного в документ). -
update: Вызывается при обновлении VNode компонента, но может произойти до обновления его дочерних VNode. Значение инструкции может измениться, а может и не измениться. Но вы можете игнорировать ненужные обновления шаблона, сравнив значения до и после обновления. -
componentUpdated: VNode компонента, в котором находится инструкцияи его дочерние VNodesВызывается после всех обновлений. -
unbind: Вызывается только один раз, когда инструкция отсоединяется от элемента.
Vue3.0Объект директивы содержит6крючки:
-
beforeMount: вызывается, когда директива впервые привязывается к элементу. можно сделать здесьОдноразовыйначальные настройки. -
mounted: вызывается, когда связанный элемент вставляется в родительский узел. -
beforeUpdate: при обновлении VNode компонента, в котором он находитсяДопередача. -
updated: VNode компонента, в котором находится инструкцияи его дочерние VNodesВызывается после всех обновлений. -
beforeUnmount: Вызывается перед размонтированием родительского компонента связанного элемента. (Сравните Vue2.xновый) -
unmounted: Вызывается только один раз, когда директива не привязана к элементу, а родительский компонент размонтирован.
В Vue3.0 из-за поддержки фрагментов компоненты могут иметь несколько корневых узлов, и использование пользовательских директив может вызвать проблемы. Крючки, содержащиеся в пользовательском объекте директивы, будут упакованы и внедрены в данные Vnode как хуки жизненного цикла Vnode.
<!-- Vue3.0 自定义指令对象包含的钩子包装后 -->
{
onVnodeMounted(vnode) {
// call vDemo.mounted(...)
}
}
При использовании пользовательских директив в компонентах этиonVnodeXXXХуки будут передаваться непосредственно компоненту как несвязанные свойства, которые можно подключить непосредственно к жизненному циклу элемента в шаблоне, подобном этому.(这里不太明白,之后试验过再来更新)
<div @vnodeMounted="myHook" />
Когда дочерний компонент используется во внутреннем элементеv-bind="$attrs", он также применит к нему любые пользовательские директивы.
Встроенные компоненты доставкиTeleport
Встроенный Vue3.0<teleport>Компонент может отправить шаблон в другое место,
<!-- Vue3.0 <teleport>传送组件 -->
<body>
<div id="app" class="demo">
<h3>Move the #content with the portal component</h3>
<div>
<teleport to="#endofbody">
<p id="content">
This should be moved to #endofbody.
</p>
</teleport>
<span>This content should be nested</span>
</div>
</div>
<div id="endofbody"></div>
</body>
если<teleport>Включите компонент Vue, и он все равно будет<teleport>Логический дочерний элемент родительского компонента, то есть даже если дочерний элемент будет отрендерен в другом месте, он все равно будет дочерним элементом родителя и будет получать от родителяprop.
Использование нескольких транспортных компонентовБудет использовать логику накопления, вот так
<teleport to="#modals">
<div>A</div>
</teleport>
<teleport to="#modals">
<div>B</div>
</teleport>
<!-- 结果 B 渲染在 A 后面 -->
<div id="modals">
<div>A</div>
<div>B</div>
</div>
функция рендеринга
Vue2.xфункция рендерингаПараметрыcreateElement
Vue3.0функция рендерингапараметрыcreateVNode(Название ближе к тому, что оно на самом деле означает, возвращая виртуальный DOM)
будет такжеhВ качестве псевдонима в Vue3.0 можно напрямую передатьVue.hПолучать
const app = Vue.createApp({})
app.component('anchored-heading', {
render() {
const { h } = Vue
return h(
'h' + this.level, // tag name
{}, // props/attributes
this.$slots.default() // array of children
)
},
props: {
level: {
type: Number,
required: true
}
}
})
События и ключевые модификаторыVue2.x предоставляет соответствующие префиксы для модификаторов событий .passive, .capture и .once, которые можно использовать на:
| модификатор | приставка |
|---|---|
.passive |
& |
.capture |
! |
.once |
~ |
.capture.onceили |
|
.once.capture |
~! |
<!-- Vue2.x 对修饰符使用前缀 -->
on: {
'!click': this.doThisInCapturingMode,
'~keyup': this.doThisOnce,
'~!mouseover': this.doThisOnceInCapturingMode
}
Vue3.0 использует синтаксис объекта
<!-- Vue3.0 对修饰符使用对象语法 -->
render() {
return Vue.h('input', {
onClick: {
handler: this.doThisInCapturingMode,
capture: true
},
onKeyUp: {
handler: this.doThisOnce,
once: true
},
onMouseOver: {
handler: this.doThisOnceInCapturingMode,
once: true,
capture: true
},
})
}
плагин
разработать плагинVue3.0 все еще необходимо предоставитьinstallметод, передать два параметра, первый параметр передаетсяVue.createAppСконструированный объект, второй необязательный параметр передается пользователемoptions
// plugins/i18n.js
export default {
install: (app, options) => {
// Plugin code goes here
}
}
Выставляется в плагине черезapp.config.globalPropertiesглобальный метод регистрации собственности
// plugins/i18n.js
<!-- 通过 app.config.globalProperties 全局注入 translate 方法 -->
export default {
install: (app, options) => {
app.config.globalProperties.$translate = (key) => {
return key.split('.')
.reduce((o, i) => { if (o) return o[i] }, i18n)
}
}
}
также черезinjectпредоставить метод или свойство пользователю
// plugins/i18n.js
<!-- 这样组件里就可以通过 inject 访问 i18n 和 options -->
export default {
install: (app, options) => {
app.config.globalProperties.$translate = (key) => {
return key.split('.')
.reduce((o, i) => { if (o) return o[i] }, i18n)
}
app.provide('i18n')
}
}
<!-- 然后就可以通过 inject['i18n'] 把 i18n 注入组件并访问 -->
Используйте плагинывсе еще черезuse()Метод может принимать два параметра, первый параметр — это подключаемый модуль, который будет использоваться, а второй параметр является необязательным и будет передан подключаемому модулю.
import { createApp } from 'vue'
import App from './App.vue'
import i18nPlugin from './plugins/i18n'
const app = createApp(App)
const i18nStrings = {
greetings: {
hi: 'Hallo!'
}
}
app.use(i18nPlugin, i18nStrings)
app.mount('#app')
Отзывчивые принципы
Отзывчивая система
Как мы все знаем,Vue2.xчерезObject.definePropertyВ сочетании с моделью публикации / подписки для достижения.
Передайте экземпляр Vuedata, Vue будет проходитьdataобъект принадлежитpropertyи использоватьObject.definePropertyПреобразуйте все эти свойства вgetter/setter, чтобы отслеживать зависимости при доступе к свойствам и их изменении. Каждый экземпляр компонента соответствуетwatcherinstance, который записывает «затронутые» свойства данных как зависимости во время рендеринга компонента. когда зависимостиsetterПри срабатывании он уведомитwatcher, вызывая повторный рендеринг связанного с ним компонента.
ProxyПрокси для перехвата доступа к целевому объекту.
Передайте экземпляр Vuedata, Vue преобразует его вProxy. Это позволяет VUE выполняться при доступе или изменении свойств.отслеживание зависимостейтак же какуведомление об изменении. Каждое свойство считается зависимостью.
После первоначального рендеринга компонент будет отслеживать зависимости (то есть свойства, к которым он обращался во время рендеринга). Другими словами, компонент становится свойством этих свойств.подписчик. Когда прокси перехватываетsetПри работе это свойство будет уведомлять своих подписчиков о повторном рендеринге.
const dinner = {
meal: 'tacos'
}
const handler = {
get(target, prop, receiver) {
track(target, prop) // Track the function that changes it 依赖项跟踪
return Reflect.get(...arguments)
},
set(target, key, value, receiver) {
trigger(target, key) // Trigger the function so it can update the final value 更改通知
return Reflect.set(...arguments)
}
}
const proxy = new Proxy(dinner, handler)
console.log(proxy.meal)
// intercepted!
// tacos
Стоит отметить, что исходный объект и прокси-объектне равныйиз
const obj = {}
const wrapped = new Proxy(obj, handlers)
console.log(obj === wrapped) // false
Основы реактивности
объявить реактивное состояниеreactive
reactiveМетод принимает обычный объект в качестве параметра, а затем возвращает реактивный прокси для обычного объекта (эквивалентно Vue2.xVue.observable()) для создания реактивного свойства. Реактивные преобразования являются «глубокими», и возвращаемый прокси-объект не равен оригиналу. Во время компиляции шаблонаrenderМетод использует эти реактивные свойства.
import { reactive } from 'vue'
// reactive state
const state = reactive({
count: 0
})
Также можно создавать реактивные свойства только для чтения, тоже глубокие, и любые вложенные свойства внутри объекта также доступны только для чтения.
const original = reactive({ count: 0 })
const copy = readonly(original)
// mutating original will trigger watchers relying on the copy
original.count++
// mutating the copy will fail and result in a warning
copy.count++ // warning: "Set operation on key 'count' failed: target is readonly."
Создание автономных реактивных свойствrefs
refМетод принимает параметр примитивного значения, а также возвращает реактивный изменяемый объект ссылки. Если это значение типа-примитива, поскольку значение типа-примитива передается по значению, а не по ссылке, это будет похоже на обертывание значения типа-примитива в объект для обеспечения отклика, но этот объект содержит только уникальные свойства.value. А для ссылочных типов он вызоветreactiveметод глубокой реактивной трансформации.
import { ref } from 'vue'
const count = ref(0)
console.log(count.value) // 0
count.value++
console.log(count.value) // 1
когдаrefКак имущество, возвращенное в контексте рендеринга и доступа к шаблону, внутреннийvalue, поэтому нет необходимости использоватьxx.valueспособ получить к нему доступ, точно так же, как доступ к обычному свойству. хочу注意, автоматическая распаковкаvalueПроисходит только при вложенных реактивныхобъектПри входе из массива илиMapОн не будет автоматически распаковываться при доступе к собственному классу коллекции, и его по-прежнему необходимо.value.
<template>
<div>
<span>{{ count }}</span>
<button @click="count ++">Increment count</button>
</div>
</template>
<script>
import { ref } from 'vue'
export default {
setup() {
const count = ref(0)
return {
count
}
}
}
</script>
Кроме того, если новыйrefназначить существующему свойству, которое заменит староеref
const otherCount = ref(2)
state.count = otherCount
console.log(state.count) // 2
console.log(count.value) // 1
рассчитать
computedметод
пройти черезcomputedметод может быть непосредственноСоздать вычисляемое значение, получитьgetterФункция принимает в качестве параметра и возвращает реактивный объект, который нельзя изменить вручную.
const count = ref(1)
const plusOne = computed(() => count.value++)
console.log(plusOne.value) // 2
plusOne.value++ // error
Или вы можете пройти вgetterа такжеsetterметод создания реактивного объекта, который можно изменить вручную
const count = ref(1)
const plusOne = computed({
get: () => count.value + 1,
set: val => {
count.value = val - 1
}
})
plusOne.value = 1
console.log(count.value) // 0
монитор
watchEffectметод
watchEffectметодОн может прослушивать зависимости, он немедленно запускает входящую функцию и отслеживает зависимости функции, а когда зависимости обновляются, немедленно выполняет функцию снова.
const count = ref(0)
watchEffect(() => console.log(count.value))
// -> logs 0
setTimeout(() => {
count.value++
// -> logs 1
}, 100)
когдаwatchEffectв компонентеsetup()Или при вызове в обработчике жизненного цикла слушатель автоматически связывается с жизненным циклом компонента и автоматически останавливается, когда компонент размонтирован. или явным вызовомwatchEffectвозвращаемое значение, чтобы прекратить прослушивание.
const stop = watchEffect(() => {
/* ... */
})
Vue3
// 之后
stop()
Аннулирование побочного эффекта
иногдаwatchEffectМетод, выполняемый в, может быть асинхронным,watchEffectПереданная функция может получитьonInvalidateв качестве параметра для регистрации обратного вызова в случае сбоя очистки, он будетwatchEffectпри повторном выполнении илиwatchEffectпрекращается (еслиsetup()или生命周期钩子используется вwatchEffect, выполняется при удалении компонента).
watchEffect(onInvalidate => {
const token = performAsyncOperation(id.value)
onInvalidate(() => {
// id 改变时 或 停止侦听时
// 取消之前的异步操作
token.cancel()
})
})
Уведомлениеsetup()будет вызываться перед монтированием компонента, поэтому, если вы хотитеwatchEffectиспользуется вDOM(или компонент), пожалуйста, объявите об этом в установленном крюкеwatchEffect
onMounted(() => {
watchEffect(() => {
// access the DOM or template refs
})
})
так же может бытьwatchEffectПередайте дополнительный объект в качестве параметра.
Например, установивflushустанавливатьwatchEffectВыполнять ли асинхронно или до обновления компонента
// 同步运行
watchEffect(
() => {
/* ... */
},
{
flush: 'sync'
}
)
// 组件更新前执行
watchEffect(
() => {
/* ... */
},
{
flush: 'pre'
}
)
onTrack(вызывается при трассировке зависимостей) иonTrigger(сработало изменение зависимостиwatchEffectметод при срабатывании) параметры можно использовать для отладкиwatchEffectповедение
watchEffect(
() => {
/* side effect */
},
{
onTrigger(e) {
debugger
}
}
)
watchв сравнении сwatchEffect,watchОн инерт, но также явно изменял состояние, что запускает слушателя, чтобы повторно запустить, и может получить доступ до доступа до и после изменения значения свойства, слушающего.
// 侦听一个 getter
const state = reactive({ count: 0 })
watch(
() => state.count,
(count, prevCount) => {
/* ... */
}
)
// 直接侦听一个 ref
const count = ref(0)
watch(count, (count, prevCount) => {
/* ... */
})
// 侦听多个数据源
watch([fooRef, barRef], ([foo, bar], [prevFoo, prevBar]) => {
/* ... */
})
API композиции
В обычном бизнесе мы часто извлекаем повторно используемые компоненты, такие как функции фильтрации, функции поиска, бизнес-списки и так далее. Но когда компонент комбинируется очень большой, список логики, на которой следует сосредоточиться (входящие компоненты), соответственно увеличивается, что может затруднить чтение и понимание, особенно для тех, кто не писал их изначально. Итак, мы хотим составить код, связанный с логикой, что такжеComposition APIизиспользовать.
<!-- 没有 Composition API 时我们通常这样做 -->
<!-- 将逻辑关系标记为相同的数字 -->
// src/components/UserRepositories.vue
export default {
components: { RepositoriesFilters, RepositoriesSortBy, RepositoriesList },
props: {
user: { type: String }
},
data () {
return {
repositories: [], // 1
filters: { ... }, // 3
searchQuery: '' // 2
}
},
computed: {
filteredRepositories () { ... }, // 3
repositoriesMatchingSearchQuery () { ... }, // 2
},
watch: {
user: 'getUserRepositories' // 1
},
methods: {
getUserRepositories () {
// using `this.user` to fetch user repositories
}, // 2
updateFilters () { ... }, // 3
},
mounted () {
this.getUserRepositories() // 1
}
}
настройка параметров компонента
setupПараметры нового компонента, используемые в сборке иComposition APIвходная точка.
setupМетод принимает 2 параметра.
Первый параметрprops, это вsetupОн также отзывчив внутренне (будьте осторожны, чтобы неpropsИспользуйте назначение деструктурирования напрямую, что нарушит отзывчивость, но вы можете использоватьtoRefsдля достижения безопасного разрушения).
// MyBook.vue
import { toRefs } from 'vue'
setup(props) {
const { title } = toRefs(props)
console.log(title.value)
}
Второй параметрcontextЭто обычный объект (не отвечает) и обнажает 3 компонентных свойства.
// MyBook.vue
export default {
setup(props, context) {
// Attributes (Reactive Property)
console.log(context.attrs)
// Slots (Reactive Property)
console.log(context.slots)
// Emit Events (Method)
console.log(context.emit)
}
}
setupОн будет выполнен после инициализации реквизита до создания экземпляра компонента, поэтому доступ к нему возможен толькоprops,attrs,slots,emit, без доступа к внутренним компонентамdata,computed,methods. Уведомлениеsetup()ВнутреннийthisНе будет ссылкой на экземпляр Vue.
setupОбъект можно вернуть, все его свойства будут доступны для других опций компонента (computedхарактеристики,methods, хуки жизненного цикла и т. д.) и шаблоны компонентов. Также возможно вернуть функцию рендеринга, которая может напрямую использовать реактивное состояние, объявленное в той же области видимости:
Composition APIТакже включает хуки жизненного цикла, аналогичные параметрам компонента, но с префиксомonXXXимена какmountedсоответствуетonMounted, который принимает обратный вызов, который будет выполняться при вызове хука компонента.
| Options API |
setupзацепить |
|---|---|
beforeCreate |
ненужный |
created |
ненужный |
beforeMount |
onBeforeMountonMounted |
mounted |
onMounted |
beforeUpdate |
onBeforeUpdate |
updated |
onUpdated |
beforeUnmount |
onBeforeUnmount |
unmounted |
onUnmounted |
errorCaptured |
onErrorCaptured |
renderTracked |
onRenderTracked |
renderTriggered |
onRenderTriggered |
из-заsetupвокругbeforeCreateа такжеcreatedЗапускаются хуки жизненного цикла, то есть любой код, который будет написан в этих двух хуках, должен бытьsetupнаписано в.
Composition APIтакже содержитwatchметод, принимает 3 параметра, первый параметр — это реактивный объект, который мы хотим прослушать или который содержитgetterфункция, второй параметр — это обратный вызов, а третий параметр — необязательный параметр конфигурации.
Также упоминалось вышеComposition APIизcomputedметод для создания вычисляемого свойства вне компонента
Таким образом, мы можем переписать приведенный выше каштан следующим образом, всякий раз, когда мы вызываемgetUserRepositoriesметод,repositoriesИзменения будут внесены оперативно, и представление будет обновлено.
// src/composables/useUserRepositories.js
import { fetchUserRepositories } from '@/api/repositories'
import { ref, onMounted, watch, toRefs } from 'vue'
export default function useUserRepositories(user) {
// 数据列表(创建一个响应式对象)
const repositories = ref([])
// 更新数据列表的方法
const getUserRepositories = async () => {
repositories.value = await fetchUserRepositories(user.value)
}
onMounted(getUserRepositories)
// 在 user 上设置一个侦听器
watch(user, getUserRepositories)
// 返回列表和方法,以在其他组件选项中访问它们
return {
repositories,
getUserRepositories
}
}
// src/components/UserRepositories.vue
// 在组件中引入 useUserRepositorie), useRepositoryNameSearch和 useRepositoryFilters
import { toRefs } from 'vue'
import useUserRepositories from '@/composables/useUserRepositories'
import useRepositoryNameSearch from '@/composables/useRepositoryNameSearch'
import useRepositoryFilters from '@/composables/useRepositoryFilters'
export default {
components: { RepositoriesFilters, RepositoriesSortBy, RepositoriesList },
props: {
user: { type: String }
},
setup(props) {
const { user } = toRefs(props)
const { repositories, getUserRepositories } = useUserRepositories(user)
const {
searchQuery,
repositoriesMatchingSearchQuery
} = useRepositoryNameSearch(repositories)
const {
filters,
updateFilters,
filteredRepositories
} = useRepositoryFilters(repositoriesMatchingSearchQuery)
return {
// 只关心过滤后的结果,因此可以以 repositories 这样的名称暴露出去
repositories: filteredRepositories,
getUserRepositories,
searchQuery,
filters,
updateFilters
}
}
}
существуетsetupтакже можно использовать вprovide / inject, четноеprovideРеактивное состояние, обратите внимание, что из-за одностороннего потока данных неinjectвводится как реактивное состояние, но вprovideпредоставляется в реактивном состоянии.
import { ref, reactive } from 'vue'
// in provider
setup() {
const book = reactive({
title: 'Vue 3 Guide',
author: 'Vue Team'
})
const year = ref('2020') // 也可以提供一个响应式状态,尽量在provide时注入为响应式状态
provide('book', book)
provide('year', year) // 如果要提供多个值,可以之后再次调用 provide
}
// in consumer
setup() {
const book = inject('book', 'Eloquent Javasctipt') /* 可选的参数默认值 */
const year = inject('year')
return { book, year }
}
существуетsetupСредний, Отзывчивыйrefsи шаблонrefsявляется унифицированным, чтобы получить ссылку на экземпляр элемента или компонента в шаблоне, вы можетеsetupОбъявите Ref и верните его. Мы хотели бы этоrootэкспонируется в контексте рендеринга и передаетсяref="root"будет привязан кdivкак егоref. В алгоритме виртуального DOM, если ref виртуального узла соответствует ref контекста рендеринга, то этому ref будет присвоен экземпляр элемента или компонента, соответствующий виртуальному узлу, который выполняется при монтировании виртуального DOM или изменен, поэтому ссылка на шаблон доступна только после инициализации рендеринга.
<template>
<div ref="root">This is a root element</div>
<div v-for="(item, i) in list" :ref="el => { divs[i] = el }">
{{ item }}
</div>
</template>
<script>
import { ref, onMounted } from 'vue'
export default {
setup() {
const root = ref(null)
const divs = ref([])
onMounted(() => {
// 在初始化后 DOM 元素将会被分配给 ref
console.log(root.value) // <div>This is a root element</div>
})
// 在每次更新前重置引用
onBeforeUpdate(() => {
divs.value = []
})
return {
root,
divs
}
}
}
</script>
Набор инструментов адаптивной системы
unref
если параметр являетсяrefВерни этоvalue, иначе возвращается сам параметр. этоval = isRef(val) ? val.value : valсинтаксический сахар.
function useFoo(x: number | Ref<number>) {
const unwrapped = unref(x) // unwrapped 一定是 number 类型
}
toRef
toRefМожет использоваться для создания ссылки на свойство реактивного объекта. Этот ref может быть передан и остается отзывчивым. toRef пригодится, когда вы хотите передать свойство свойства как ссылку на комбинаторную логическую функцию.
const state = reactive({
foo: 1,
bar: 2,
})
const fooRef = toRef(state, 'foo')
fooRef.value++
console.log(state.foo) // 2
state.foo++
console.log(fooRef.value) // 3
toRefs
Преобразование реактивного объекта в обычный объект, каждое свойство нормального объекта представляет собой ref , который соответствует свойству реактивного объекта один к одному. Использование toRefs полезно, когда вы хотите вернуть реактивные объекты из комбинаторной логической функции, этот API позволяет потребляющим компонентам деконструировать/расширять (используя оператор ...) возвращаемый объект без потери отклика.
isRef
Проверяет, является ли значение объектом ссылки.
isProxy
Проверяет, создан ли объектreactiveилиreadonlyметод создания прокси.
isReactive
Проверяет, создан ли объектreactiveСоздал реактивный прокси. Если этот прокси сделанreadonlyсоздан, но затемreactiveДругой созданный прокси оборачивает слой, а затем также возвращаетtrue.
isReadonly
Проверяет, создан ли объектreadonlyСоздал прокси только для чтения.
const state = reactive({
foo: 1,
bar: 2,
})
const stateAsRefs = toRefs(state)
/*
stateAsRefs 的类型如下:
{
foo: Ref<number>,
bar: Ref<number>
}
*/
// ref 对象 与 原属性的引用是 "链接" 上的
state.foo++
console.log(stateAsRefs.foo) // 2
stateAsRefs.foo.value++
console.log(state.foo) // 3
API расширенной адаптивной системы
customRef
customRefдля пользовательскогоref, вы можете явно управлять отслеживанием зависимостей и триггерным ответом, принимать фабричную функцию, для отслеживания используются два параметраtrackс тем, который использовался для запуска ответаtriggerи возвращает массив сgetа такжеsetобъект недвижимости
Это каштан, который использует пользовательскую ссылку для реализации v-модели с функцией защиты от сотрясений.
<input v-model="text" />
function useDebouncedRef(value, delay = 200) {
let timeout
return customRef((track, trigger) => {
return {
get() {
track()
return value
},
set(newValue) {
clearTimeout(timeout)
timeout = setTimeout(() => {
value = newValue
trigger()
}, delay)
},
}
})
}
export default {
setup() {
return {
text: useDebouncedRef('hello'),
}
},
}
markRaw
Явно помечая объект как «никогда не превращаться в реактивный прокси», функция возвращает сам объект.
shallowReactive
Создавайте поверхностный реактивный прокси только для частных (первого уровня) свойств объекта, не делайте глубокий рекурсивный реактивный прокси для «свойств свойства», а просто оставьте его как есть.
shallowReadonly
Создайте неглубокий реактивный прокси только для чтения только для собственных свойств объекта (первого уровня), а также не будет выполнять глубокое, рекурсивное проксирование, а свойства глубокого уровня не доступны только для чтения.
shallowRef
Создаватьref, будет отслеживать его.valueизменить операцию, но это не влияет на измененную.valueВыполняйте реактивные преобразования прокси (т. е. изменения не вызываютreactive)
toRaw
вернулсяreactiveилиreadonlyМетоды конвертируются в простые объекты для реактивных прокси. Это метод возврата, который можно использовать для временного чтения, доступ не проксируется/отслеживается, а изменения не инициируются при записи. Не рекомендуется постоянно хранить ссылку на исходный объект. Пожалуйста, используйте с осторожностью.
А также добавить несколько моментов. первый,Vue3.0черезTypeScriptРефакторинг, проверка типов ts значительно снижает вероятность внесения неожиданных ошибок и снижает нагрузку на техническое обслуживание.
Vue3.0Оптимизация алгоритма виртуального DOM, при обнаружении всех узлов шаблон может быть разбит на вложенный блок, разделенный этими структурными инструкциями, для инструкции шаблона без динамического изменения структуры узла (например, использованиеv-ifилиv-for), структура узлов этого блока статична, и генерируемый им код будет удален из функции рендеринга. Каждый раз, когда эти объекты необходимо повторно отображать, их не нужно создавать повторно, что также увеличивает использование памяти и снижает частоту сборки мусора. На уровне элемента компилятор создает флаг оптимизации для элементов с динамическими привязками в зависимости от типа обновления, которое необходимо выполнить, которое среда выполнения выбирает и выбирает более быстрый путь.
а такжеVue3.0Перенесено через большинство глобальных API и помощниковmodule.exportsхарактеристики. такmodule bundlerМожет статически анализировать зависимости модуля, удалять код, связанный с неиспользуемыми атрибутами module.exports, и генерировать код, удобный для встряхивания дерева Когда функция фактически используется в шаблоне, вспомогательная функция для этой функции импортируется.
Несмотря на то, что было добавлено много новых функций,Vue3.0Соотношение сжатого размераVue2.xПоловина размера!
Выше приведены различия, обнаруженные при сравнении содержания учебника.Самое главное, чтоComposition APIа такжеReactivityЭто также самая сложная часть для меня. Кроме того, документация Vue3.0 все еще находится в стадии разработки, и в последующем могут быть некоторые изменения. Пожалуйста, обратитесь к документации. Мы не приступили к разработке напрямую, поэтому я не высказывал слишком много личных мнений. , только в сравнении с Vue2.x.