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 - ваши друзья.

Другие вопросы по тегам