API композиции Vue 3 и доступ к экземпляру Vue
В main.js
У меня примерно так:
import { myUtilFunc} from './helpers';
Object.defineProperty(Vue.prototype, '$myUtilFunc', { value: myUtilFunc });
Таким образом у меня есть доступ к myUtilFunc
во всем приложении с this.$myUtilFunc
Но как я могу добиться того же в setup()
в Vue 3, если у меня нет доступа к this
?
2 ответа
В Vue 3 setup
имеет необязательный второй аргумент для context
. Вы можете получить доступ к экземпляру Vue черезcontext.root
вместо того this
:
setup(props, context) {
context.root.$myUtilFunc // same as `this.$myUtilFunc` in Vue 2
}
Вещи, через которые можно получить доступ context
:
context.attrs
context.slots
context.parent
context.root
context.emit
Хотя ответ Дэна правильный, я хотел бы предоставить альтернативу, упомянутую в комментариях к принятому ответу. У каждого есть свои плюсы и минусы, поэтому вам нужно выбирать, исходя из ваших потребностей.
Чтобы понять, почему приведенный ниже код работает, важно помнить, что предоставленные свойства являются транзитивными в дереве компонентов. Т.е.inject('foo')
будет искать "foo" в каждом родительском элементе, идущем вверх по иерархии вплоть до app
; в средних оболочках ничего объявлять не нужно.
Итак, мы можем написать что-то вроде этого, где globalDateFormatter() - это просто пример функции, которую мы хотим использовать в любом компоненте вниз по дереву:
main.js
import { createApp } from 'vue'
import App from './App.vue'
const globalDateFormatter = (date) => {
return '[' + date.toLocaleString() + ']'
}
const app = createApp(App)
app.provide('globalDateFormatter', globalDateFormatter) // <-- define here
app.mount('#app')
А затем в каком-нибудь DeepDownComponent.vue:
<template>
<p> {{ fmt(new Date()) }} </p>
</template>
<script>
import { inject } from 'vue'
export default {
setup(){
const fmt = inject('globalDateFormatter', x => x.toString())
// ^-- use here, optional 2nd parameter is the default
return {fmt}
}
}
</script>
Очевидно, вы можете напрямую импортировать и использовать provide
а также inject
со следующими подписями
provide<T>(key: InjectionKey<T> | string, value: T): void
а также
inject<T>(key: InjectionKey<T> | string, defaultValue: T): T
где угодно в вашем коде, не обязательно app.provide()
Вы также можете указать значения, даже в глобальном хранилище, вот так, просто не забудьте использовать ref()
или reactive()
по мере необходимости.
Короче говоря, всякий раз, когда вы предпочитаете инъекцию зависимостей, provide/inject - ваши друзья.