Предусмотрен для всех, чтобы изучить на ранней стадии, и теперь вы можете перейти на китайский документ
v3.cn.vuejs.orgВремя модификации 21 сентября 2020 г. --- Официальная версия vue3 была выпущена вечером 18 сентября 2020 г.
Разница между глобальными изменениями API конфигурации Vue2 и Vue3
createApp
-
Vue2.x создает экземпляр и монтирует его в DOM.
import Vue from "vue"; import App from './App.vue' new Vue({ render: (h) => h(App) }).$mount("#app"); -
Vue3 добавляет api===>createAppАдрес источникаСоздать экземпляр
createAppсоздаст экземпляр приложения с глобальным настраиваемым контекстомimport { createApp } from 'vue' import App from './App.vue' createApp(App).mount('#app')
что делает createApp

- Метод sureRenderer возвращается в самый низДобавьте patchclass+patchStyle и другие методы, связанные с манипулированием DOM.
- sureRenderer (создает виртуальный DOM) возвращается полностью назадcreateRenderer и baseCreateRenderer, метод baseCreateRenderer включает в себя создание и обновление алгоритма DIFF виртуального DOM
- После этого стоит проверить, смонтировано ли монтирование на DOM.
- объект приложенияВышеуказанные методы: конфигурация, использование, миксин, компонент, директива, монтирование, размонтирование, предоставление/внедрение.
component
-
Vue2.x [Зарегистрируйтесь или получите глобальные компоненты. Регистрация также автоматически использует данный
idУстановите имя компонента]// 注册组件,传入一个选项对象 (自动调用 Vue.extend) Vue.component('my-component', { /* ... */ }) // 获取注册的组件 (始终返回构造器) var MyComponent = Vue.component('my-component') -
Vue3 [зарегистрируйте или получите глобальные компоненты. При регистрации также будет автоматически использоваться данный компонент имени для установки имени компонента]глобальный компонент
Базовая запись vue2 такая же
import { createApp } from 'vue' const app = createApp({}) // 注册组件,传入一个选项对象 app.component('my-component', { /* ... */ }) // 获取注册的组件 (始终返回构造器) const MyComponent = app.component('my-component', {})
config【приложение=создать приложение(приложение)】
devtools
Разрешена ли конфигурацияvue-devtoolsПроверьте код. Версия для разработчиков по умолчанию
true, производственная версия по умолчаниюfalse. Производственная версия настроена наtrueМожно включить проверку.
- Vue.config.devtools = true
+ app.config.devtools = true
errorHandler
- Vue.config.errorHandler = function (err, vm, info) {
// handle error
// `info` 是 Vue 特定的错误信息,比如错误所在的生命周期钩子
// 只在 2.2.0+ 可用
}
+ app.config.errorHandler = (err, vm, info) => {
// handle error
// `info` 是 Vue 特定的错误信息,比如错误所在的生命周期钩子
// 这里能发现错误
}
Указывает обработчик необработанных ошибок во время рендеринга и просмотра компонента. Когда этот обработчик вызывается, он получает сообщение об ошибке и экземпляр Vue.
служба отслеживания ошибокSentryиBugsnagОба обеспечивают официальную поддержку через эту опцию.
warnHandler
- Vue.config.warnHandler = function (msg, vm, trace) {
// `trace` 是组件的继承关系追踪
}
+ app.config.warnHandler = function(msg, vm, trace) {
// `trace` 是组件的继承关系追踪
}
Предоставляет собственный обработчик предупреждений среды выполнения Vue. Обратите внимание, что это будет работать только в средах разработки и будет игнорироваться в производственных средах.
globalProperties[Добавлены свойства]
app.config.globalProperties.foo = 'bar'
app.component('child-component', {
mounted() {
console.log(this.foo) // 'bar'
}
})
Добавьте глобальные свойства, к которым можно получить доступ в любом экземпляре компонента в программе. При наличии конфликта ключей приоритет имеют свойства компонента.
Замените свойство Vue.prototype Vue2.x и поместите его в прототип.
// Vue2.x
Vue.prototype.$http = () => {}
// Vue3
const app = Vue.createApp({})
app.config.globalProperties.$http = () => {}
isCustomElement[Добавлены свойства]
- Замена ignoredElements Vue2.x
- Vue.config.ignoredElements = [
// 用一个 `RegExp` 忽略所有“ion-”开头的元素
// 仅在 2.5+ 支持
/^ion-/
]
// 一些组件以'ion-'开头将会被解析为自定义组件
+ app.config.isCustomElement = tag => tag.startsWith('ion-')
Укажите метод распознавания пользовательских компонентов, определенных вне Vue (например, с помощьюWeb Component API). Если компонент соответствует этому условию, ему не требуется локальная или глобальная регистрация, и Vue не выдает предупреждения о неизвестном пользовательском элементе.
Обратите внимание, что в этой функции нет необходимости сопоставлять всю нативную разметку HTML и SVG — синтаксический анализатор Vue выполняет эту проверку автоматически.
optionMergeStrategies
const app = Vue.createApp({
mounted() {
console.log(this.$options.hello)
}
})
app.config.optionMergeStrategies.hello = (parent, child, vm) => {
return `Hello, ${child}`
}
app.mixin({
hello: 'Vue'
})
// 'Hello, Vue
Определите стратегию слияния для пользовательских параметров.
Стратегия слияния получена вродительский экземплярoptions в качестве первого и второго аргументов соответственно. Экземпляр контекста Vue передается в качестве третьего параметра.
【Стратегия слияния пользовательских опций】mixin
const app = Vue.createApp({
custom: 'hello!'
})
app.config.optionMergeStrategies.custom = (toVal, fromVal) => {
console.log(fromVal, toVal)
// => "goodbye!", undefined
// => "hello!", "goodbye!"
return fromVal || toVal
}
app.mixin({
custom: 'goodbye!',
created() {
console.log(this.$options.custom) // => "hello!"
}
})
- optionMergeStrategies сначала получает смесь $options дочернего экземпляра без родительского экземпляра [сначала настраиваемые изменения с undefined на goodbye ---> print "goodbye!", undefined]
- родительского экземпляраварианты [настраиваемый от до свидания до привет во второй раз! ---> напечатано "привет", "до свидания!"]
- Наконец, напечатайте $options родительского экземпляра, возвращенного app.config.optionMergeStrategies.custom.
Во всяком случае это.options, затем вернитесь к расчету и другим операциям, чтобы получить требуемое значение] optionMergeStrategies объединяет изменения $options
performance
- Vue.config.performance=true;
+ app.config.performance=true;
Установите значение true, чтобы включить отслеживание производительности при инициализации, компиляции, рендеринге и исправлении компонентов на панели производительности/временной шкалы инструментов разработчика браузера. Доступно только в режиме разработки и в браузерах, поддерживающих API performance.mark.
directiveУчебная документация
Зарегистрируйтесь или получите глобальные директивы.
import { createApp } from 'vue'
const app = createApp({})
// 注册
app.directive('my-directive', {
// 指令的生命周期
// 在绑定元素的父组件被挂载之前调用
beforeMount(el, binding, vnode) {},
// 在挂载绑定元素的父组件时调用
mounted(el, binding, vnode) {},
// 在更新包含组件的VNode之前调用
beforeUpdate(el, binding, vnode, prevNode) {},
// 组件的VNode及其子组件的VNode更新之后调用
updated(el, binding, vnode, prevNode) {},
// 在卸载绑定元素的父组件之前调用
beforeUnmount(el, binding, vnode) {},
// 在卸载绑定元素的父组件时调用
unmounted(el, binding, vnode) {}
})
// 注册 (指令函数)
app.directive('my-directive', (el, binding, vnode, prevNode) => {
// 这里将会被 `mounted` 和 `updated` 调用
})
// getter,返回已注册的指令
const myDirective = app.directive('my-directive')


-
el
Элемент, к которому привязана директива. Это можно использовать для прямого управления DOM.
-
привязка [объект, содержащий следующие свойства]
-
instance: экземпляр компонента, который использует директиву
-
значение: значение привязки директивы, например:
v-my-directive="1 + 1", значение привязки равно2 -
oldValue: предыдущее значение, связанное с директивой, только если
beforeUpdateиupdatedВ наличии крючки. Доступно независимо от того, изменилось ли значение -
arg: Параметр, передаваемый инструкции, необязательный. Например
v-my-directive:foo, параметры"foo" -
модификаторы: объект, содержащий модификаторы. Например:
v-my-directive.foo.bar, объект модификатора{ foo: true, bar: true } -
dir: объект, передаваемый в качестве параметра при регистрации директивы; например, см. следующую директиву
app.directive('focus', { mounted(el) { el.focus() } })dir — это следующий объект
{ mounted(el) { el.focus() } }
-
-
vnode
Скомпилируйте сгенерированный виртуальный узел
-
prevNode
Предыдущий виртуальный узел, доступный только в beforeUpdate и обновленных хуках
советы: кроме
elКроме того, другие параметры должны быть доступны только для чтения, их нельзя изменять. Если вам нужно обмениваться данными между хуками, рекомендуется передать элементdatasetвыполнять
миксин [базовый согласованный с Vue2.x]
- Эффект optionMergeStrategies можно увидеть выше.
Глобальная регистрация миксина влияет на каждый экземпляр Vue, созданный после регистрации. Авторы плагинов могут использовать примеси для внедрения пользовательского поведения в компоненты.Не рекомендуется использовать в коде приложения.
монтировать [аналогично Vue2.x]
Подключает корневой компонент экземпляра приложения к предоставленному элементу DOM.
import { createApp } from 'vue'
const app = createApp({})
// 做一些准备
app.mount('#my-app')
предоставить/внедрить [согласованный с Vue2.x]
Эта опция, используемая с inject, позволяет компоненту-предку быть инжектором зависимостей для всех своих потомков, независимо от того, насколько глубока иерархия компонентов, если они находятся в одной и той же родительской цепочке.
provideОпции должны быть объектом или функцией, возвращающей объект. Этот объект содержит свойства, которые можно внедрить в его потомков. В этом объекте вы можете использовать символы ES2015 в качестве ключей, но только в родной поддержке.SymbolиReflect.ownKeysрабочая обстановка.
Если в компоненте оба могут использоваться только в текущем активном экземпляре компонента
setup()Вызывается в разделе «Внедрение зависимостей» для получения подробной информации.
import { createApp } from 'vue'
const app = createApp({
provide: {
user: 'John Doe'
}
})
app.component('user-card', {
inject: ['user'],
template: `
<div>
{{ user }}
</div>
`
})
размонтировать [новый атрибут]
Размонтирует корневой компонент экземпляра приложения в предоставленном элементе DOM.
import { createApp } from 'vue'
const app = createApp({})
// 做一些必要的准备
app.mount('#my-app')
// 应用程序将在挂载后5秒被卸载
setTimeout(() => app.unmount('#my-app'), 5000)
используйте [согласованный с Vue2.x]
Установите плагин Vue.js. Если плагин является объектом, необходимо указатьinstallметод. Если плагин является функцией, он будет использоваться как метод установки. Когда вызывается метод установки, Vue передается в качестве параметра.
Когда метод установки вызывается одним и тем же плагином несколько раз, плагин будет установлен только один раз.
setup
setupФункции — это новая опция компонента. как используется в компонентеComposition APIточка входа
- Уведомление
setupВозвращенный ref будет автоматически развернут в шаблоне, не нужно писать.value【setupВнутренние потребности.value】
время вызова
-
Создайте экземпляр компонента, затем инициализируйте
props, затем позвонитеsetupфункция. С точки зрения крючков жизненного цикла это будетbeforeCreateхук был вызван раньше -
если
setupВозвращает объект, свойства которого будут объединены в контекст рендеринга шаблона компонента.
параметр
-
propsв качестве первого аргумента
Уведомление
propsОбъекты реактивны,watchEffectилиwatchбуду наблюдать и отвечатьpropsОбновитьне хотетьДеконструкция
propsобъект, который сделал бы его невосприимчивым
export default {
props: {
name: String,
},
setup(props) {
console.log(props.name)
watchEffect(() => {
console.log(`name is: ` + props.name)
})
},
}
-
Второй параметр предоставляет объект контекста [из оригинального 2.x
thisНекоторые свойства доступны выборочно (attrs/emit/slots)]attrsиslotsОба являются прокси для соответствующего элемента во внутреннем экземпляре компонента, гарантируя актуальность значения после обновления. Таким образом, вы можете деконструировать, не беспокоясь о доступе к просроченным значениям позже.Почему реквизит в качестве первого параметра?
- Использование компонентов
propsбольше сценариев, а иногда даже просто использоватьprops - будет
propsРазделенный в качестве первого параметра, позволяет TypeScriptpropsВывод типа выполняется отдельно и его нельзя спутать с другими свойствами в контексте. Это также делаетsetup,renderСоответствует сигнатурам других функциональных компонентов, использующих TSX.
thisсуществуетsetup()не доступно в. так какsetup()Вызывается перед разбором опций 2.x,setup()серединаthisБудет работать с опциями 2.x вthisполностью отличается. в то же времяsetup()и используются варианты 2.xthisвызовет путаницуsetup(props, { attrs }) { // 一个可能之后回调用的签名 function onClick() { console.log(attrs.foo) // 一定是最新的引用,没有丢失响应性 } }

- Использование компонентов
API реактивной системы
reactive
desc: реактивный прокси, который принимает простой объект и возвращает этот простой объект [эквивалентно 2.xVue.observable()】
-
ssss
tips:
ProxyОбъект является прокси для целевого объекта, и любые операции над целевым объектом (создание экземпляра, добавление/удаление/изменение свойств и т. д.) должны проходить через прокси. Поэтому мы можем перехватывать, фильтровать или модифицировать все операции из внешнего мира.
Реактивные преобразования являются «глубокими»: они затрагивают все вложенные свойства внутри объекта. На основе реализации Proxy ES2015 возвращаемый прокси-объектне равнооригинальный объект. Рекомендуется использовать только прокси-объекты и не полагаться на исходные объекты.
reactiveAPI класса в основном обеспечивает возможность обработки сложных типов данных в отзывчивые данные, Фактически, этот сложный тип должен использоваться вobject array map set weakmap weaksetСреди этих пяти видов [следующий исходный код, он рассудит, есть ли пять категорий и заморожены ли они]

Поскольку это составная функция [объект], вы всегда должны поддерживать ссылку на возвращаемый объект, чтобы поддерживать отзывчивость [не может деконструировать объект или расширять] Например
const { x, y } = useMousePosition()илиreturn { ...useMousePosition() }
function useMousePosition() {
const pos = reactive({
x: 0,
y: 0,
})
return pos
}
toRefsAPI используется для решения этого ограничения — он превращает каждое свойство реактивного объекта в соответствующую ссылку [превращает объект в ссылку].function useMousePosition() { const pos = reactive({ x: 0, y: 0, }) return toRefs(pos) } // x & y 现在是 ref 形式了! const { x, y } = useMousePosition()
ref
Принимает значение параметра и возвращает реактивный и изменяемый объект ссылки. Объекты ref имеют одно свойство, указывающее на внутреннее значение.value
const count = ref(0)
console.log(count.value) // 0
Если переданная ссылка является объектом, она вызовет
reactiveметод глубокой адаптивной трансформации
ловушка
-
setupсерединаreturnВозврат будет автоматически развернут [не требуется в шаблоне.value】
-
Когда ref используется или изменяется как свойство реактивного объекта, он также будет автоматически развернут.
.valueconst count = ref(0) /*当做reactive的对象属性----解套*/ const state = reactive({ count, }) /* 不需要.value*/ console.log(state.count) // 0 /*修改reactive的值*/ state.count = 1 /*修改了ref的值*/ console.log(count.value) // 1Обратите внимание, что если вы назначите новую ссылку существующей ссылке, старая ссылка будет заменена.
/*创建一个新的ref*/ const otherCount = ref(2) /*赋值给reactive的旧的ref,旧的会被替换掉*/ state.count = otherCount /*修改reactive会修改otherCount*/ console.log(state.count) // 2 /*修改reactive会count没有被修改 */ console.log(count.value) // 1 -
вложенный в реактивный
ObjectВ середине ссылка будет развернута. отArrayилиMapПри доступе к ref в собственном классе коллекции он не будет автоматически развернут [свободный тип данных — Object, пока он не будет развернут.arraymapsetweakmapweaksetКласс коллекцииПри обращении к ref он не разворачивается автоматически】const arr = reactive([ref(0)]) // 这里需要 .value console.log(arr[0].value) const map = reactive(new Map([['foo', ref(0)]])) // 这里需要 .value console.log(map.get('foo').value)
умственное бремяref vs reactive
- Разница в простом JavaScript
声明基础类型变量и对象变量использовать то же самоеrefиreactive - используется везде
reactive, затем не забудьте использовать, когда функция композиции возвращает реактивный объектtoRefs. Это снижает часть умственной нагрузки на судей.
readonly
Передать объект (реактивный или обычный) или ссылку, вернуть ссылку на исходный объекттолько чтениеиграет роль. Прокси-сервер только для чтения является «глубоким», и любые вложенные свойства внутри объекта также доступны только для чтения [возвращает прокси-сервер только для чтения, который никогда не изменяется] [сценарии могут соответствовать параметрам]
const original = reactive({ count: 0 })
const copy = readonly(original)
watchEffect(() => {
// 依赖追踪
console.log(copy.count)
})
// original 上的修改会触发 copy 上的侦听
original.count++
// 无法修改 copy 并会被警告
copy.count++ // warning!
reactiveНабор инструментов адаптивной системы
isProxy
Проверяет, создан ли объект
reactiveилиreadonlyПрокси, созданный по методу
isReactive
Проверяет, создан ли объект
reactiveСоздал реактивный проксиimport { reactive, isReactive } from 'vue' const state = reactive({ name: 'John' }) console.log(isReactive(state)) // -> true
Если этот прокси сделан
readonlyсоздан, но затемreactiveДругой созданный прокси оборачивает слой, а затем также возвращаетtrueimport { reactive, isReactive, readonly } from 'vue' const state = reactive({ name: 'John' }) // 用readonly创建一个只读响应式对象plain const plain = readonly({ name: 'Mary' }) //readonly创建的,所以isReactive为false console.log(isReactive(plain)) // -> false // reactive创建的响应式代理对象包裹一层readonly,isReactive也是true,isReadonly也是true const stateCopy = readonly(state) console.log(isReactive(stateCopy)) // -> true
isReadonly
Проверяет, создан ли объект
readonlyСоздан прокси только для чтения
reactiveAPI расширенной адаптивной системы
toRaw
вернулся
reactiveилиreadonlyМетоды конвертируются в простые объекты для реактивных прокси. Это метод возврата, который можно использовать для временного чтения, доступ не проксируется/отслеживается, а изменения не инициируются при записи. Не рекомендуется сохранять ссылку на исходный объект**不建议赋值给任何变量**]. Пожалуйста, используйте с осторожностью
одеяло**toRawОбъекты после ** являются обычными объектами, которые не проксируются/не отслеживаются.
const foo = {}
const reactiveFoo = reactive(foo)
console.log(toRaw(reactiveFoo) === foo) // true
console.log(toRaw(reactiveFoo) !== reactiveFoo) // true
markRaw
Явно разметки объекта как «никогда не превращается в реактивный прокси», функция возвращает сам объект.
【
markRawПри передаче объекта возвращаемое значение никогда не будет преобразовано в реактивный прокси]const foo = markRaw({ name: 'Mary' }) console.log(isReactive(reactive(foo))) // false
Отмечено markRaw, даже если оно является свойством адаптивного объекта, оно все равно не является адаптивным.
const bar = reactive({ foo }) console.log(isReactive(bar.foo)) // false
markRawбудь осторожен
-
API семейств markRaw и smallXXX позволяютпо желанию«Глубокая» функция, созданная реактивной или готовностью [ответом] / или использует неравномерно обычный объект
-
Дизайн этого «поверхностного чтения» имеет много причин
- Фактическое использование некоторых значений очень простое, и нет необходимости превращать их в адаптивные [например, экземпляры трехсторонних библиотек/провинций/городских объектов json/компонентов Vue]
- При рендеринге большого количества элементов, но данные неизменяемы, пропуск преобразования прокси может привести к повышению производительности.
-
Эти API считаются высокоуровневыми, потому что эта функция остается только на корневом уровне, поэтому, если вы сделаете вложенный, не будет
markRawОбъект устанавливается как свойство реактивного объекта, и при повторном посещении вы снова получите прокси-версию, что в конечном итоге приведет кПутаница с логотипомСерьезная проблема: выполнение операции, которая зависит как от исходной версии, так и от прокси-версии объекта (путаница идентификации должна быть очень редкой в общем использовании, но чтобы полностью избежать таких проблем, необходимо понимать всю реактивную систему. Там достаточно четкое представление о том, как это работает).const foo = markRaw({ nested: {}, }) const bar = reactive({ // 尽管 `foo` 己经被标记为 raw 了, 但 foo.nested 并没有 nested: foo.nested, }) console.log(foo.nested === bar.nested) // false- foo.nested не помечен (никогда не превращался в реактивный прокси), что приводит к реактивному последнему значению

shallowReactive
Создайте только неглубокий реактивный прокси для частных (первого уровня) свойств объекта, а не глубокий рекурсивный реактивный прокси для «свойств свойства», но просто оставьте все как есть [первый слой — это реактивный прокси, только глубокий уровень остается как есть (без отзывчивого прокси)]
const state = shallowReactive({
foo: 1,
nested: {
bar: 2,
},
})
// 变更 state 的自有属性是响应式的【第一层次响应式】
state.foo++
// ...但不会深层代理【深层次不是响应式】(渲染性能)
isReactive(state.nested) // false
state.nested.bar++ // 非响应式
shallowReadonly
похожий наshallowReactive, разница:
- Первый слой будет реактивным прокси [первый слой не сможет изменить свойства], а свойства будут реактивными.
- Свойства глубинного объекта могут быть изменены, свойства не являются реактивными
const state = shallowReadonly({
foo: 1,
nested: {
bar: 2,
},
})
// 变更 state 的自有属性会失败
state.foo++
// ...但是嵌套的对象是可以变更的
isReadonly(state.nested) // false
state.nested.bar++ // 嵌套属性依然可修改
refНабор инструментов адаптивной системы
unref
unrefдаval = isRef(val) ? val.value : valсинтаксический сахар для
unref(ref(0))===unref(0)===0 返回number
function useFoo(x: number | Ref<number>) {
const unwrapped = unref(x) // unwrapped 一定是 number 类型
}
toRef
toRefМожет использоваться для реактивного объекта属性[Свойство отличает каждое свойство toRefs] Создайте ссылку. Этот ref может быть передан и остается отзывчивым
const state = reactive({
foo: 1,
bar: 2,
})
//reactive获取单个属性转为ref【fooRef只是一个代理】
const fooRef = toRef(state, 'foo')
fooRef.value++
console.log(state.foo) // 2
state.foo++
console.log(fooRef.value) // 3
toRefs
Преобразование отзывчивого объекта в обычный объект, каждое свойство обычного объекта представляет собой ref , взаимно однозначное соответствие со свойством отзывчивого объекта.
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
в состоянии пройти
toRefsвозвращает разрушаемый реактив, потому чтоtoRefsПосле переноса верните соответствующий атрибут ref один к одному.function useFeatureX() { const state = reactive({ foo: 1, bar: 2, }) // 对 state 的逻辑操作 // 返回时将属性都转为 ref return toRefs(state) } export default { setup() { // 可以解构,不会丢失响应性 const { foo, bar } = useFeatureX() return { foo, bar, } }, }
isRef
Проверить, является ли значение объектом ссылки
refAPI расширенной адаптивной системы
customRef
для пользовательскогоref, вы можете явно управлять отслеживанием зависимостей и триггерным ответом, принимать фабричную функцию, для отслеживания используются два параметраtrackс тем, который использовался для запуска ответаtriggerи возвращает массив сgetиsetОбъект атрибута [фактически ручнойtrackотслеживать иtriggerЗапустить ответ]
- Следующий код может сделать v-модель анти-встряхиванием
function useDebouncedRef(value, delay = 200) {
let timeout
return customRef((track, trigger) => {
return {
get() {
/*初始化手动追踪依赖讲究什么时候去触发依赖收集*/
track()
return value
},
set(newValue) {
/*修改数据的时候会把上一次的定时器清除【防抖】*/
clearTimeout(timeout)
timeout = setTimeout(() => {
/*把新设置的数据给到ref数据源*/
value = newValue
/*再有依赖追踪的前提下触发响应式*/
trigger()
}, delay)
},
}
})
}
setup() {
return {
/*暴露返回的数据加防抖*/
text: useDebouncedRef('hello'),
}
}
shallowRef
Создайте реф, который будет отслеживать его.valueизменить операцию, но это не влияет на измененную.valueВыполнять реактивные преобразования прокси (т. е. изменения не вызываютreactive)
Ранее мы говорили, что если переданная ссылка является объектом, она вызовет
reactiveметод для выполнения глубоких преобразований ответа, черезshallowRefСозданный ref не будет называться реактивным [объект не будет реактивным]const refOne = shallowRef({}); refOne.value = { id: 1 }; refOne.id == 20; console.log(isReactive(refOne.value),refOne.value);//false { id: 1 }
triggerRef【иshallowRefСотрудничать】
сделать это вручную с помощьюshallowRefлюбой эффект, связанный с
const shallow = shallowRef({
greet: 'Hello, world'
})
// 第一次运行打印 "Hello, world"
watchEffect(() => {
console.log(shallow.value.greet)
})
// 这不会触发效果,因为ref是shallow
shallow.value.greet = 'Hello, universe'
// 打印 "Hello, universe"
triggerRef(shallow)
Вычисляем и смотрим【Контролировать изменения】
computed
-
Передайте функцию получения и вернитеОбъект ref по умолчанию, не изменяемый вручную[По умолчанию передается объект функции get]
-
перейти во владение
getиsetобъект функции, которая создает модифицируемое вручную состояние вычисления

const count = ref(1)
/*不支持修改【只读的】 */
const plusOne = computed(() => count.value + 1)
plusOne.value++ // 错误!
/*【可更改的】 */
const plusOne = computed({
get: () => count.value + 1,
set: (val) => {
count.value = val - 1
},
})
plusOne.value = 1
console.log(count.value) // 0
watchEffect
Выполняет входящий немедленнофункция, и оперативно отслеживать его зависимости, иПерезапустите функцию при изменении ее зависимостей
computedиwatchEffectразница:
-
computedВычисляемые свойства доступны через настройкуreturn, а затем использовать в шаблоне, watchEffect не может; -
computedВы можете использовать несколько и выполнять разные расчеты ответов для нескольких свойств, watchEffect будет иметь побочные эффекты.
const count = ref(0)
watchEffect(() => console.log(count.value))
// -> 打印出 0
setTimeout(() => {
count.value++
// -> 打印出 1
}, 100)
перестань смотреть
Когда watchEffect вызывается во время функции setup() или хука жизненного цикла компонента, наблюдатель связан с жизненным циклом компонента и автоматически останавливается, когда компонент выгружается.
В целом
watchEffectВозвращает операцию остановки, чтобы остановить прослушивательconst stop = watchEffect(() => { /* ... */ }) // 停止监听程序 stop()
Побочные эффекты (функциональное программирование)
Функция с побочными эффектами не просто возвращает значение, она делает и другие вещи, например:
- изменить переменную
- Непосредственное изменение структуры данных
- Установить член объекта
- Выдает исключение или завершается с ошибкой
- распечатать на терминал или прочитать пользовательский ввод
- прочитать или записать файл
- рисовать на экране
Пример buyCoffee (p3): Функция просто должна вернуть чашку кофе, но она сохраняет комиссию (с побочными эффектами). Мы также можем вернуть комиссию как значение, когда метод buyCoffee возвращает кофе. Дана запись в другие программы для сохранения, тем самым удаляя побочные эффекты ====" Преобразуйте любую функцию с побочными эффектами, переместив эти побочные эффекты на внешний уровень программы (чистое ядро и тонкий периферийный слой для борьбы с побочными эффектами)
Если функция зависит от внешних переменных или окружения, мы часто называем это побочными эффектами. Если мы передаем только сигнатуру функции, не открывая внутреннюю проверку кода, мы не можем знать, что делает функция. Как независимая функция, мы ожидаем, что ясно Ввод и вывод, побочные эффекты являются местом рождения ошибок.Как программист, разработчики должны стараться разрабатывать функции или методы с минимальными побочными эффектами.Побочные эффекты также делают методы менее универсальными и непригодными для расширения и повторного использования.
явные побочные эффекты
[^]: все функции watchEffect являются побочными эффектами
В какой-то момент функция слушателя выполнитсяасинхронныйПобочные эффекты [реактивная зависимость модифицируется и делает что-то еще], эти ответы необходимо очищать, когда они терпят неудачу (например, изменение состояния до завершения эффекта). Функция эффекта получает функцию onInvalidate в качестве входного параметра, которая используется для регистрации обратного вызова в случае сбоя очистки. Когда будет вызвана функция инвалидации:
-
При повторном выполнении функции прослушивателя [зависимые данные изменены]
-
когда часы остановлены (если watchEffect включен
setup()Или компонент будет удален, когда он используется в функции жизненного цикла) [Прекратить наблюдение]watchEffect(onInvalidate => { /*这是个异步操作*/ const token = performAsyncOperation(id.value)//id依赖 onInvalidate(() => { // id被修改了或者监听停止了会触发token.cancel()事件【这块区域的代码】. // 这里是异步事件的话,前面的peding的异步操作无效【这里的异步事件只执行一次】 token.cancel()/*异步操作*/ console.log('onInvalidate') }) })
从上面看:我们之所以是通过传入一个函数去注册失效回调,而不是从回调返回它(如 React `useEffect` 中的方式),是因为返回值对于异步错误处理很重要
````js
const data = ref(null)
watchEffect(async onInvalidate => {
onInvalidate(() => {...}) // 我们在Promise的resolves之前注册清理函数(cleanup function)
data.value = await fetchData(props.id)
})
Мы знаем, что асинхронные функции неявно возвращают обещание, ноФункции, устраняющие побочные эффектыДолжен быть разрешен в Promiseранее зарегистрированный. Кроме того, Vue полагается на этот возвращенный промис для автоматической обработки потенциальных ошибок в цепочке промисов.
Время обновления побочных эффектов
Отзывчивая система Vue будетКэшировать побочные эффекты, и сбрасывать их асинхронно, что позволяет избежать ненужного дублирования вызовов, вызванных несколькими изменениями состояния в одном такте. В конкретной реализации ядра функция обновления компонента также является побочным эффектом. Когда пользовательская функция побочного эффекта ставится в очередь,Выполнить после обновления всех компонентов
<template>
<div>{{ count }}</div>
</template>
<script>
export default {
setup() {
const count = ref(0)
watchEffect(() => {
console.log(count.value)
})
return {
count,
}
},
}
</script>
-
countбудет распечатан синхронно при первом запуске -
Изменять
countкогда компонент будетОбновленовыполнять побочные эффектыЗапуск инициализации находится в компоненте
mountedранее выполненный [вы хотите получить доступ к DOM (или ссылке на шаблон) при написании функций с побочными эффектами, пожалуйстаonMountedна крючке]onMounted(() => { watchEffect(() => { // 在这里可以访问到 DOM 或者 template refs }) })
Если побочный эффект необходимо синхронизировать или перезапустить перед обновлением компонента, мы можем передать
flushобъект свойств в качестве опций (по умолчанию'post')// 同步运行 watchEffect( () => { /* ... */ }, { flush: 'sync', } ) // 组件更新前执行 watchEffect( () => { /* ... */ }, { flush: 'pre', } )
Отладка прослушивателя [для адаптивной отладки]
onTrackиonTriggerПараметры можно использовать для отладки поведения слушателя.
- Вызывается, когда свойство реактивного объекта или ссылка отслеживаются как зависимость
onTrack[Количество звонков — это номер, который нужно отслеживать] - Изменения зависимостей вызывают повторное отслеживание зависимостей, таким образом
onTrackЗвонили [количество звонков равно количеству отслеженных] - Вызывается, когда изменение зависимости вызывает запуск побочных эффектов
onTrigger
Оба обратных вызова получат событие отладчика, содержащее информацию о зависимости. Рекомендуется писать в следующем обратном вызовеdebuggerоператор для проверки зависимостей: [onTrackиonTriggerРаботает только в режиме разработки】
watchEffect(
() => {
/* 副作用的内容 */
},
{
onTrigger(e) {
/*副作用依赖修改*/
debugger
},
onTrack(e) {
/*副作用依赖修改*/
debugger
},
}
)

watch
watchAPI полностью эквивалентен 2.xwatchв соответствующих опциях.watchНеобходимо прослушивать определенный источник данных и выполнять побочные эффекты в функции обратного вызова [по умолчанию используется отложенное выполнение, что означает, что обратный вызов выполняется только при изменении источника прослушивания]
watchПозвольте нам:
- Ленивые побочные эффекты
- Больше ясности в том, какие изменения состояния заставляют слушателя повторно запускать побочные эффекты.
- Доступ к значениям до и после прослушивания изменений состояния
Слушайте один источник данных
Источником данных прослушивателя может быть функция-получатель с возвращаемым значением или ссылка:
// 侦听一个 getter
const state = reactive({ count: 0 })
watch(
() => state.count,
(count, prevCount) => {
/* ... */
}
)
// 直接侦听一个 ref
const count = ref(0)
watch(count, (count, prevCount) => {
/* ... */
})
Слушайте несколько источников данных
watcherТакже можно использовать массив для одновременного прослушивания нескольких источников.watch([fooRef, barRef], ([foo, bar], [prevFoo, prevBar]) => { /* ... */ })
иwatchEffectобщее поведение
смотреть и смотретьЭффект вперестань слушать, явные побочные эффекты(соответственноonInvalidateбудет передан в качестве третьего параметра обратного вызова),Время обновления побочных эффектовиОтладка прослушивателяпоследовательное поведение
watch([fooRef, barRef], ([foo, bar], [prevFoo, prevBar],onInvalidate) => {
/* ... */
onInvalidate(() => {...})
},
{
onTrigger(e) {
/*副作用依赖修改*/
debugger
},
onTrack(e) {
/*副作用依赖修改*/
debugger
},
})
Функция хука жизненного цикла
Составные API, соответствующие жизненному циклу версии 2.x.
-
-> использоватьbeforeCreatesetup() -
-> использоватьcreatedsetup() -
beforeMount->onBeforeMount -
mounted->onMounted -
beforeUpdate->onBeforeUpdate -
updated->onUpdated -
beforeDestroy->onBeforeUnmount -
destroyed->onUnmounted -
errorCaptured->onErrorCaptured
import { onMounted, onUpdated, onUnmounted } from 'vue'
setup() {
onMounted(() => {
console.log('mounted!')
})
onUpdated(() => {
console.log('updated!')
})
onUnmounted(() => {
console.log('unmounted!')
})
}
Эти функции регистрации хуков жизненного цикла могут использоваться только вsetup()используются синхронно во времяsetup()экземпляр компонента), вызов этих функций без текущего компонента вызывает ошибку.
Контекст экземпляра компонента также устанавливается во время синхронного выполнения обработчика жизненного цикла, поэтому, когда компонент выгружается, прослушиватели и вычисляемое состояние, созданные синхронно внутри обработчика жизненного цикла, также автоматически удаляются.
Добавлена функция хука
В дополнение к эквивалентам жизненного цикла 2.x API композиции предоставляет следующие перехватчики отладки:
onRenderTrackedonRenderTriggered
Обе функции ловушек получаютDebuggerEvent,иwatchEffectв опциях параметровonTrackиonTriggerпохожий:
export default {
onRenderTracked(e){
debugger
// 检查有响应和追踪的依赖性
},
onRenderTriggered(e) {
debugger
// 检查哪个依赖性导致组件重新渲染
},
}
Встроенные компоненты, предоставляемые Vue
компонент совместим с Vue2.x
Визуализирует «метакомпонент» как динамический компонент. в соответствии сisзначение, чтобы определить, какой компонент визуализируется.
<!-- 动态组件由 vm 实例的 `componentId` property 控制 -->
<component :is="componentId"></component>
<!-- 也能够渲染注册过的组件或 prop 传入的组件 -->
<component :is="$options.components.child"></component>
Существуют различия между переходом и Vue2.x [Basic]
-
Новый реквизит:
-
persisted-booleanЕсли это правда, это означает, что это переход, который на самом деле не вставляет/удаляет элементы, а переключает состояние отображения/скрытия. хуки перехода вводятся, но пропускаются визуализатором. Вместо этого пользовательские директивы могут управлять переходами, вызывая встроенные хуки (например, v-show). -
----->enter-classenter-from-class -
----->leave-classleave-from-class
-
- событие
before-appear
группа перехода соответствует Vue2.x
слот совместим с Vue2.x
телепорт 【Новый компонент】
-
Props
-
to-stringОбязательный атрибут должен быть допустимым селектором запроса или элементом (если используется в среде браузера). будет помещен в указанный целевой элемент<!-- 正确的 --> <teleport to="#some-id" /> <teleport to=".some-class" /> /*元素*/ <teleport to="[data-teleport]" /> <!-- 错误的 --> <teleport to="h1" /> <teleport to="some-string" /> -
disabled-booleanЭто необязательно, выполнение одного из них — это функция, которую можно использовать для отключения, что означает, что содержимое его слота никуда не перемещается, а не нажимается.teleportКомпонент обычно визуализируется [по умолчанию false]<teleport to="#popup" :disabled="displayVideoInline"> <h1>999999</h1> </teleport>Обратите внимание, что это приведет к перемещению фактического узла DOM вместо уничтожения и воссоздания, а также сохранит все экземпляры компонентов. Все элементы HTML с состоянием (например, воспроизводимое видео) сохранят свое состояние. [Управление displayVideoInline не уничтожает и не перестраивает, оно сохраняет экземпляр существующим и не будет выходить из системы]
-
О телепорте Другой контент
Vue побуждает нас создавать пользовательский интерфейс, инкапсулируя пользовательский интерфейс и связанное с ним поведение в компоненты. Мы можем вложить их друг в друга, чтобы построить дерево, составляющее пользовательский интерфейс приложения.
Однако иногда часть шаблона компонента логически принадлежит этому компоненту, и с технической точки зрения лучше переместить эту часть шаблона в другое место в DOM, за пределы приложения Vue.
Распространенным сценарием является создание компонента, содержащего полноэкранное модальное окно. В большинстве случаев вы хотите, чтобы логика модального окна находилась в компоненте, но позиционирование модального окна быстро становится трудным для решения с помощью CSS или требует изменения состава компонента.
Рассмотрим следующую структуру HTML:
<body>
<div style="position: relative;">
<h3>Tooltips with Vue 3 Teleport</h3>
<div>
<modal-button></modal-button>
</div>
</div>
</body>
покажи намmode -button
Компонент будет иметьbuttonэлемент, вызывающий открытие модального окна, и элемент div с классом .modal, который будет содержать содержимое модального окна и кнопку самозакрытия.
const app = Vue.createApp({});
app.component('modal-button', {
template: `
<button @click="modalOpen = true">
Open full screen modal!
</button>
<div v-if="modalOpen" class="modal">
<div>
I'm a modal!
<button @click="modalOpen = false">
Close
</button>
</div>
</div>
`,
data() {
return {
modalOpen: false
}
}
})
При использовании этого компонента в исходной HTML-структуре мы видим проблему — модальное окно отображается в глубоко вложенном div, а абсолютная позиция модального окна указывается относительно родительского div.


Teleport предоставляет простой способ, позволяющий нам контролировать, под каким родительским узлом в DOM мы хотим отображать фрагменты HTML, не прибегая к глобальному состоянию или разбивая его на два компонента.
Давайте изменим нашу модальную кнопку для использования и скажем Vue «телепортировать этот HTML в тег «body»».
app.component('modal-button', {
template: `
<button @click="modalOpen = true">
Open full screen modal! (With teleport!)
</button>
<teleport to="body">
<div v-if="modalOpen" class="modal">
<div>
I'm a teleported modal!
(My parent is "body")
<button @click="modalOpen = false">
Close
</button>
</div>
</div>
</teleport>
`,
data() {
return {
modalOpen: false
}
}
})


Использование с компонентами Vue
Если компонент Vue включен, он все равно будет логическим дочерним элементом родительского компонента.
const app = Vue.createApp({
template: `
<h1>Root instance</h1>
<parent-component />
`
})
app.component('parent-component', {
template: `
<h2>This is a parent component</h2>
<teleport to="#endofbody">
<child-component name="John" />
</teleport>
`
})
app.component('child-component', {
props: ['name'],
template: `
<div>Hello, {{ name }}</div>
`
})
В этом случае, даже если рендерится в другом местеchild-component, все равно будетparent-componenдочерний компонент [вместо компонента дедушки] и получит реквизит имени от своего родительского компонента
Это также означает, что внедрение из родительского компонента работает должным образом, а дочерний компонент будет вложен под родительский компонент в Vue Devtools, а не туда, куда перемещается фактическое содержимое.
Использование нескольких телепортов для одной и той же цели
Обычный сценарий использования — повторно используемый компонент, который может иметь несколько активных экземпляров одновременно. В этом сценарии несколько компонентов могут подключать свое содержимое к одному и тому же целевому элементу. Порядок будет простым добавлением — более поздние монтирования будут следовать за более ранними монтированиями в целевом элементе.
<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>
Внедрение зависимостей Предоставить/внедрить
provideиinjectОбеспечивает внедрение зависимостей, аналогично 2.x.provide/inject. Оба могут использоваться только в текущем активном экземпляре компонента.setup()вызывать
Например, если мы хотим указать название книги в корневом компоненте и внедрить его в дочерние компоненты.
import { provide, inject } from 'vue'
const RootComponent = {
setup() {
provide('book', 'Vue 3 guide')
}
}
const MyBook = {
setup() {
const book = inject(
'book',
'Eloquent Javascript' /* 选项的默认值,假如父组件不提供值就返回默认 */
)
return {
book
}
}
}
injectПринимает необязательное значение по умолчанию в качестве второго параметра. Если значение по умолчанию не указано и свойство не найдено в контексте предоставления, тогдаinjectвозвращениеundefined.
Если нам нужно предоставить или внедрить несколько значений, мы можем сделать это, последовательно вызвав предоставление или внедрение соответственно [несколько вызовов]
import { provide, inject } from 'vue'
const RootComponent = {
setup() {
provide('book', 'Vue 3 guide')
provide('year', '2020')
}
}
const MyBook = {
setup() {
const book = inject(
'book',
'Eloquent Javascript' /* 选项的默认值,假如父组件不提供值就返回默认 */
)
const year = inject('year')
return {
book,
year
}
}
}
Инжектированная отзывчивость
можно использоватьrefилиreactiveгарантироватьprovidedиinjectedотклик между значениями
import { ref, reactive } from 'vue'
// 提供者
setup() {
const book = reactive({
title: 'Vue 3 Guide',
author: 'Vue Team'
})
const year = ref('2020')
/*提供reactive响应式*/
provide('book', book)
/*提供ref响应式*/
provide('year', year)
}
// 消费者
setup() {
const book = inject('book')
const year = inject('year')
/*响应式*/
return { book, year }
}
Теперь, когда книга или год меняются в компоненте-поставщике, мы можем наблюдать, как они меняются в компоненте-инжекте.
Предупреждение: мы не рекомендуем изменять введенное реактивное свойство [дочерний компонент для изменения потока данных], так как это нарушит односторонний поток данных Vue. Вместо этого попробуйте изменить значение там, где оно указано [родительский компонент для изменения], или предоставьте метод для изменения значения.
import { ref, reactive } from 'vue' // in provider setup() { const book = reactive({ title: 'Vue 3 Guide', author: 'Vue Team' }) function changeBookName() { book.title = 'Vue 3 Advanced Guide' } provide('book', book) provide('changeBookName', changeBookName) } // in consumer setup() { const book = inject('book') const changeBookName = inject('changeBookName') return { book, changeBookName } }
инструкция
v-текст [согласованный с Vue2.x]
v-html [согласованный с Vue2.x]
v-show [согласованный с Vue2.x]
v-if [согласованный с Vue2.x]
v-else [согласованный с Vue2.x]
v-else-if [согласованный с Vue2.x]
v-for [согласованный с Vue2.x]
v-on [согласованный с Vue2.x]
v-связать [Vue2.xмодификаторразница】
модификатор
-
Удалить.prop -
Удалить.sync -
.camelПреобразование имен атрибутов kebab-case в camelCase
v-модель [согласованная с Vue2.x]
v-слот [согласованный с Vue2.x]
v-плащ [согласованный с Vue2.x]
v-once [согласованный с Vue2.x]
v-pre [согласованный с Vue2.x]
v-это [новый]
Примечание. Этот раздел касается только случая, когда шаблон Vue написан непосредственно в HTML-коде страницы.
-
Ограничение: нативные html-элементы
-
использовать:
При использовании шаблона в DOM шаблон должен подчиняться собственным правилам синтаксического анализа HTML. Некоторые элементы HTML (например,
- ,
- , и ) имеют ограничения на то, какие элементы могут находиться внутри них, в то время как некоторые элементы (например, и ) могут появляться только внутри некоторых других элементов. Решение состоит в том, что мы можем использовать директиву v-is для этих элементов [роль заключается в преобразовании имени компонента]
Предупреждение v-это функциональность, подобная динамической версии 2.x.
:isпривязка, поэтому для отображения компонента на основе зарегистрированного имени его значение должно быть строкой javascript<!-- 不正确的, 不会出现任何渲染 --> <tr v-is="blog-post-row"></tr> <!-- 正确 --> <tr v-is="'blog-post-row'"></tr>
Глобальный API
createApp
Возвращает экземпляр приложения, чтобы обеспечить контекст приложения. Вся компонентное дерево, установленное экземпляром приложения, имеет тот же контекст
const app = Vue.createApp({})параметр
- Функция получает объект опций корневого компонента в качестве первого параметра.
const app = Vue.createApp({ data() { return { ... } }, methods: {...}, computed: {...} setup(){...} ... })- Используя второй параметр, мы можем передать реквизиты корневого компонента приложению.
<div id="app"> <!-- 这里将会显示 'Evan' --> {{ username }} </div> const app = Vue.createApp( { props: ['username'] }, { username: 'Evan' } )
h
Возвращает «виртуальный узел», часто сокращенно VNode: простой объект, содержащий информацию, описывающую тип узла, который Vue должен отображать на странице, включая описания любых дочерних узлов. вы можете прочитать вручнуюrender functions
render() { return Vue.h('h1', {}, 'Some title') }параметр
принимает три параметра
tag,propsandchildren-
tag:
- тип:
String | Object | Function | null - Подробности: имя тега HTML, компонент, асинхронный компонент или нуль. Использование null будет отображаться как комментарий. Этот параметр обязателен
- тип:
-
props
- тип:
Object - Детали: объекты, соответствующие атрибутам, свойствам и событиям, используемым в шаблоне. по желанию
- тип:
-
children
-
тип:
String | Array | Object -
Подробности:
Дочерние виртуальные узлы, созданные с помощью h(), или строка для получения «текстовых виртуальных узлов» или объектов со слотами. по желанию
-
const aaa = { props: { someProp: String }, setup(props) { console.log(props, "dsadasdasddasds"); }, render() { return h( "h2", // {Object}props //与props,attributes和events相对应的对象 //我们将在template中使用。 // 可选的。 {style: {"font-size": "20px", color: "#136"}}, [this.someProp,this.$slots.default()]); } }; app.component("anchored-heading", { render() { return h( /* // {String | Object | Function | null}标签 // HTML标记名称,组件,异步组件或null。 //使用null将渲染注释。 //必填 */ "h" + this.level, // tag name // {Object}props //与props,attributes和events相对应的对象 //我们将在template中使用。 // 可选的。 {}, // {String | Array | Object} children //使用`h()`构建的子级VNode, //或使用字符串获取“文本VNodes”或 //具有插槽的对象。 // 可选的。 [ "Some text comes first.", h("h1", "A headline"), h(aaa, { someProp: "foobar" }) ] );}, });
Vue.h( 'a', { name: headingId, href: '#' + headingId }, this.$slots.default() ) ])ограничение
VNODES должен быть уникальным
-
Все вноды в дереве компонентов должны быть уникальными. Это означает, что функция рендеринга ниже недействительна.
render() { const myParagraphVNode = Vue.h('p', 'hi') return Vue.h('div', [ // 表示惊讶 - 副本复制 VNodes! myParagraphVNode, myParagraphVNode ]) } -
Если вы действительно хотите скопировать один и тот же элемент/компонент несколько раз, вы можете использовать для этого фабричную функцию. Например, следующая функция рендеринга — очень эффективный способ рендеринга 20 одинаковых абзацев:
render() { return Vue.h('div', Array.apply(null, { length: 20 }).map(() => { return Vue.h('p', 'hi') }) ) }
Замена атрибутов шаблона простым JavaScript
v-ifandv-forЭто можно легко сделать с помощью простого JavaScript в любом месте, и ни одна из функций рендеринга Vue не предлагает проприетарной альтернативы. Например, в шаблоне с использованием v-if и v-for
<ul v-if="items.length"> <li v-for="item in items">{{ item.name }}</li> </ul> <p v-else>No items found.</p> ==> props: ['items'], render() { if (this.items.length) { return Vue.h('ul', this.items.map((item) => { return Vue.h('li', item.name) })) } else { return Vue.h('p', 'No items found.') } }v-modelДиректива v-model расширена до
modelValueиonUpdate:modelValueреквизиты Во время компиляции шаблона мы должны сами предоставить эти реквизитыprops: ['modelValue'], render() { return Vue.h(SomeComponent, { modelValue: this.modelValue, 'onUpdate:modelValue': value => this.$emit('update:modelValue', value) }) }v-onМы должны дать обработчику события соответствующее имя свойства, например, чтобы обработать
clickсобытие, название реквизита должно бытьonClickrender() { return Vue.h('div', { onClick: $event => console.log('clicked', $event.target) }) }事件修饰符Для модификаторов событий .passive, .capture и .once Vue предоставляет синтаксис объекта для обработчиков.
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 }, }) }Для всех остальных событий и ключевых модификаторов не требуется никакого специального API, потому что мы можем использовать методы событий в обработчиках.

render() { return Vue.h('input', { onKeyUp: event => { // 如果发出事件的元素不存在,则中止事件绑定到的元素 if (event.target !== event.currentTarget) return // 同时如果按下的键不是enter键key (13)以及shift键没有按下 if (!event.shiftKey || event.keyCode !== 13) return // 停止事件传播 event.stopPropagation() // 阻止此元素的默认keyup处理程序 event.preventDefault() // ... } }) }Slotsвы можете получить доступ к содержимому слота
this.$slotsв массиве VNodesrender() { // `<div><slot></slot></div>` return Vue.h('div', {}, this.$slots.default()) }props: ['message'], render() { // `<div><slot :text="message"></slot></div>` return Vue.h('div', {}, this.$slots.default({ text: this.message })) }Используйте функцию рендеринга для передачи слотов дочерним компонентам
render() { // `<div><child v-slot="props"><span>{{ props.text }}</span></child></div>` return Vue.h('div', [ Vue.h('child', {}, { // 通过`slots'作为子对象 // in the form of { name: props => VNode | Array<VNode> } default: (props) => Vue.h('span', props.text) }) ]) }JSXНаписание чего-то подобного может быть мучением, если мы собираемся написать много функций рендеринга.
Vue.h( 'anchored-heading', { level: 1 }, [Vue.h('span', 'Hello'), ' world!'] )Особенно когда версия шаблона такая лаконичная по сравнению
<anchored-heading :level="1"> <span>Hello</span> world! </anchored-heading>Вот почему есть плагин Babel для использования JSX во Vue, давайте вернемся к синтаксису ближе к шаблонам.
import AnchoredHeading from './AnchoredHeading.vue' new Vue({ el: '#demo', render() { return ( <AnchoredHeading level={1}> <span>Hello</span> world! </AnchoredHeading> ) } })определитькомпонент [компонент]
С точки зрения реализации, defineComponent будет делать только то, что возвращает переданный ему объект. Однако с точки зрения типа возвращаемое значение имеет синтетический тип функции искусственного рендеринга, конструктор, поддерживаемый инструментами TSX и IDE.
параметр
объект с параметрами компонентов
import { defineComponent } from 'vue' const MyComponent = defineComponent({ data() { return { count: 1 } }, methods: { increment() { this.count++ } } })defineAsyncComponent [асинхронный компонент]
Создавайте асинхронные компоненты, которые загружаются только при необходимости.
параметр
Для базового использования defineAsyncComponent может принимать возврат
Promiseзаводская функция. Обратный вызов разрешения Promise должен вызываться, когда вы получаете определение компонента из serve. Вы также можете вызвать reject(reason), чтобы указать на сбой загрузки.import { defineAsyncComponent } from 'vue' const AsyncComp = defineAsyncComponent(() => /*或者*/ import('./components/AsyncComponent.vue') /*或者*/ new Promise((resolve, reject) => { /*可以reject*/ resolve({ template: '<div>I am async!</div>' }) }) ) app.component('async-component', AsyncComp)При использовании локальной регистрации вы также можете напрямую указать функцию, которая возвращает Promise.
import { createApp, defineAsyncComponent } from 'vue' createApp({ // ... components: { AsyncComponent: defineAsyncComponent(() => import('./components/AsyncComponent.vue') ) } })Для расширенного использования defineAsyncComponent может принимать объект
const AsyncComp = defineAsyncComponent({ // 工厂函数 loader: () => import('./Foo.vue') // 加载异步组件时使用的组件 loadingComponent: LoadingComponent, //加载失败的时候使用的组件 errorComponent: ErrorComponent, // 在显示加载组件之前延迟。默认值:200 ms。 delay: 200, // 如果超时,将显示错误组件 // 存在timeout并且超过这个时间. 默认值:无穷 timeout: 3000, // 返回布尔值的函数,指示当加载器promise rejects时异步组件是否应该重试 retryWhen: error => error.code !== 404, // 允许的最大重试次数 maxRetries: 3, // 定义组件是否可挂载 suspensible: false })resolveComponent
Предупреждение: resolveComponent можно использовать только в
renderилиsetupиспользуется в функции.Разрешает разрешение компонента по имени, если оно доступно в текущем экземпляре приложения. Если компонент не найден, вернуть компонент или неопределенный компонент
Если компонент не найден, вернуть компонент или неопределенный компонент [component]
app.component('MyComponent', { /* ... */ }) const MyComponent = resolveComponent('MyComponent')resolveDynamicComponent [разрешить активный активный компонент]
resolveDynamicComponent можно использовать только в
renderилиsetupиспользуется в функции.разрешено использовать сcomponent:is=""Тот же механизм разрешения компонентов.
Возвращает разрешенный компонент или вновь созданный виртуальный узел, отмеченный именем компонента в качестве узла.
Предупреждать, если компонент не найден
resolveDirective
Предупреждение: resolveDirective можно использовать только в
renderилиsetupиспользуется в функции.Позволяет разрешать директиву по имени, если она доступна в текущем экземпляре приложения.
вернуть
Directiveили если не найдено, вернутьundefined.app.directive('highlight', {}) render(){ const highlightDirective = resolveDirective('highlight') }withDirectives
предупреждать
withDirectivesтолько вrenderилиsetupиспользуется в функции.::: Позволяет применять инструкции к виртуальным узлам. Возвращает VNode с примененными инструкциями.
const bar = resolveDirective('bar') return withDirectives(h('div'), [ [bar, this.y] ])createRenderer *[будет]
nextTick
Отложите обратный вызов до окончания следующего цикла обновления DOM. Используйте его сразу после изменения некоторых данных, чтобы дождаться обновления DOM.
setup() { const message = ref('Hello!') const changeMessage = async newMessage => { message.value = newMessage /*等待DOM更新*/ await nextTick() console.log('Now DOM is updated') } }методы экземпляра
$watch
параметр
{string | Function} source{Function | Object} callback-
{Object} [options]{boolean} deep{boolean} immediate
использование
Следите за изменениями в реактивных свойствах или вычисляемых функциях экземпляров компонентов. Используйте обратные вызовы для получения новых и старых значений данного свойства. Мы можем передавать только данные верхнего уровня, пропсы или имена вычисляемых свойств в виде строк. Вместо более сложных выражений или вложенных свойств используйте функции.
пример
const app = Vue.createApp({ data() { return { a: 1, b: 2, c: { d: 3, e: 4 } } }, created() { // 顶级属性名a this.$watch('a', (newVal, oldVal) => { // 做一些事 }) // 观察监视单个嵌套属性 this.$watch( () => this.c.d, (newVal, oldVal) => { // 做一些事 } ) // 监控复杂表达式 this.$watch( // 每当表达式`this.a + this.b`产生不同的结果时 // 处理程序将被调用。这就好像我们在看computed属性 // 而不定义计算属性本身 () => this.a + this.b, (newVal, oldVal) => { // 做一些事 } ) } })- Когда отслеживаемое значение является объектом или массивом, любые изменения его свойств или элементов не вызовут срабатывания наблюдателя, поскольку они относятся к тому же объекту/массиву.
const app = Vue.createApp({ data() { return { article: { text: 'Vue is awesome!' }, comments: ['Indeed!', 'I agree'] } }, created() { this.$watch('article', () => { console.log('Article changed!') }) this.$watch('comments', () => { console.log('Comments changed!') }) }, methods: { // 这些方法不会触发观察者,因为我们仅更改了对象/数组的属性, // 并不是 Object/Array 本身 changeArticleText() { this.article.text = 'Vue 3 is awesome' }, addComment() { this.comments.push('New comment') }, // 这些方法会触发观察者,因为我们完整替换了对象/数组 changeWholeArticle() { this.article = { text: 'Vue 3 is awesome' } }, clearComments() { this.comments = [] } } })- $watch возвращает функцию unwatch, которая прекращает запуск обратного вызова
const unwatch = vm.$watch('a', cb) // later, teardown the watcher unwatch()Option: deep
Чтобы обнаружить изменения значений, вложенных внутрь объекта, вам нужно передать deep: true в параметре options. Обратите внимание, что это не требуется для прослушивания изменений массива.
vm.$watch('someObject', callback, { deep: true }) vm.someObject.nestedValue = 123 // 触发回调Option: immediate
Передача немедленного: true в параметрах немедленно вызовет обратный вызов с текущим значением выражения.
vm.$watch('a', callback, { immediate: true }) // “callback”被立即触发,当前值为“a”Обратите внимание, что использование
immediateвариант, вы не сможете отменить просмотр данного свойства при первом вызове обратного вызова.//这个例子是错误的 const unwatch = vm.$watch( 'value', function() { doSomething() unwatch() }, { immediate: true } )Если вы все же хотите вызвать функцию unwatch в обратном вызове, вам следует сначала проверить ее доступность.
const unwatch = vm.$watch( 'value', function() { doSomething() if (unwatch) { unwatch() } }, { immediate: true } )$ излучать [постоянный]
$forceUpdate [согласованный]
$nextTick [согласованный]
Примеры имущества
vm.$data [согласованный]
vm.$props [согласованный]
vm.$el [согласованный]
vm.$options [согласованный]
vm.$parent [согласованный]
vm.$root [согласованный]
vm.$slots [согласованный]
vm.$refs [согласованный]
vm.$attrs [согласованный]


Устаревший:
vm.$childrenvm.$slotsvm.$scopedSlotsvm.$isServervm.$listenersВарианты/Комбинации
миксины [постоянные]
расширяет [постоянный]
предоставлять / вводить [постоянный]
parent【Отброшено】настройка【Новый】
Подробнее см. выше
Опции/Ресурсы
директивы [последовательные]
компоненты [согласованные]
filters【Отброшено】опции/данные
данные [согласованные]
реквизит [постоянный]
вычисленный [согласованный]
методы [последовательные]
смотреть [последовательно]
испускает【Новый】
Подробности
Список/хэш пользовательских событий, которые могут быть отправлены компонентом. Он имеет простой синтаксис на основе массива и альтернативный синтаксис на основе объектов, который позволяет настраивать проверку событий.
В синтаксисе на основе объектов значение каждого свойства может быть нулевым или функцией проверки. Функция проверки будет переданаemit('foo',1), соответствующий валидатор foo получит параметр 1. Функция валидатора должна возвращать логическое значение, чтобы указать, допустим ли параметр события.
const app = Vue.createApp({}) // 数组语法 app.component('todo-item', { emits: ['check'], created() { this.$emit('check') } }) // 对象语法 app.component('reply-form', { emits: { // 无效 click: null, // 有效 submit: payload => { if (payload.email && payload.password) { return true } else { console.warn(`Invalid submit event payload!`) return false } } } })Совет. События, перечисленные в опции emit, не будут наследоваться корневым элементом компонента [
