【问题标题】:Access this.$root in Vue.js 3 setup()在 Vue.js 3 setup() 中访问 this.$root
【发布时间】:2021-01-10 09:11:06
【问题描述】:

在 Vue 2 中,您可以在 created 挂钩中访问 this.$root。在 Vue 3 中,本来可以在 created 挂钩中的所有内容现在都在 setup() 中。

setup() 中我们无法访问this,那么,我们如何访问根实例上的任何内容?

说,我在根实例上设置了一个属性:

const app = createApp(App).mount('#app');

app.$appName = 'Vue3';

我可以使用this.$root.$appNamemounted() 访问this,如何在setup() 中执行此操作?


更新

如果我import它,我可以访问它:

import app from '@/main';
...
setup() {
    console.log(app.$appName) // Vue3

但是,如果我必须对每个文件都这样做,这会很麻烦。


更新 2

另一种解决方法是在App.vue 中使用provide(),然后在任何其他组件中使用inject()

setup() {
    provide('$appName', 'Vue3')
setup() {
    inject('$appName') // Vue3

【问题讨论】:

  • console.log(this) 看看发生了什么事吗?
  • thisundefinedsetup()
  • 好吧我猜你不能访问它然后When setup is executed, the component instance has not been created yet
  • 根实例必须在组件之前存在
  • hmm.. 但你可以使用道具。也许您将根实例作为道具传递给孩子?

标签: javascript vue.js vue-component vuejs3 vue-composition-api


【解决方案1】:

看来你需要provide / inject。在你的App.vue:

import { provide } from 'vue';

export default {
  setup() {
    provide('appName', 'vue3')
  }
} 

provide 与您的app

const app = createApp(App);
app.mount('#app');

app.provide('appName', 'Vue3');

然后在您要访问此变量的任何子组件中,inject 它:

import { inject } from 'vue'

export default {
  setup() {
    const appName = inject('appName');
  }
}

【讨论】:

  • 我猜如果你正在寻找一个常量,你也可以在某个地方定义它export const appName = 'Vue3',然后在任何你想使用它的地方,你可以import { appName } from 'constant.js'
【解决方案2】:

你可以在 vue 3 中定义 global property

app.config.globalProperties.appName= 'vue3'

使用setup(composition api),您可以使用getcurrentinstance 访问该属性:

import { getCurrentInstance } from 'vue'
...
setup() {
    const app= getCurrentInstance()
    console.log(app.appContext.config.globalProperties.appName) 

由于您仍然可以使用 options api,您可以简单地做:

mounted(){
   console.log(this.appName) 
}

【讨论】:

    【解决方案3】:

    对于想知道如何在setup() 中简单地访问this 的人来说,一种方法是将this 设置为created() 挂钩中的一个记忆变量并使用nextTick() 来访问它:

    const app = createApp(App);
    
    app.config.globalProperties.$appName = 'Hello!';
    
    <script>
    import { nextTick } from 'vue';
    
    let self;
    
    export default {
        name: 'HelloWorld',
    
        setup() {
            nextTick(() => console.log(self.$appName)); // 'Hello!'
        },
    
        created() {
            self = this;
        },
    };
    </script>
    

    @Psidom's answer 在我看来是更好的做法,但这只是另一种方式。

    【讨论】:

      【解决方案4】:

      如果您只想用'Vue 3'(字符串)替换任何模板中的{{ appName }},而无需导入任何内容,最简洁的方法是使用config.globalProperties,正如其他答案所建议的那样:

      const app = createApp(App).mount('#app');
      app.config.globalProperties.appName = 'Vue 3'
      

      但是,您应尽量不要过度使用此模式。它违背了推动组合 API 开发的可重用性和模块化原则。

      您应该避免污染globalProperties 的主要原因是因为它在 Vue3 应用程序中充当污染场,因此许多插件开发人员可能决定使用它来提供他们的插件实例。 (显然,没有人会为插件命名appName,因此在这种特殊情况下您不会冒险)。

      推荐的全球化替代方法是导出 useStuff() 函数。
      在你的情况下:

      export function useAppName () { return 'Vue 3' }
      // or even:
      export const useAppName = () => 'Vue 3'
      

      在任何组件中:

      import { useAppName } from '@/path/to/function'
      
      setup () {
         const appName = useAppName()
         return {
           appName // make it available in template and hooks
         }
      }
      

      优点:

      • 它使用 Composition API 命名约定
      • 当共享比原语更复杂的东西(可能是模块、一组函数、服务等)时,所有类型都会被推断出来的盒子。这在 setup() 函数中特别有用。
      • 您只在需要的地方公开和限定stuff,而不是在应用程序的每个组件中。另一个优点是:如果您只需要在 setup() 函数中使用它,则不必将其暴露给模板或钩子。

      随机(但真实)插件的使用示例:
      创建一个插件文件(即:/plugins/gsap.ts):

      import gsap from 'gsap'
      import ScrollToPlugin from 'gsap/ScrollToPlugin'
      
      // configure the plugin globally
      gsap.registerPlugin(ScrollToPlugin)
      
      export function useGsap () {
        return gsap
      }
      

      在任何组件中:

      import { defineComponent } from 'vue'
      import { useGsap } from '@/plugins/gsap'
      
      export defineComponent({
        setup () {
          const gsap = useGsap()
            // gsap here is typed correctly (if the plugin has typings)
            // no need for casting
          return { 
            gsap  // optionally provide it to hooks and template
          }       // if needed outside setup()
        }
      })
      

      【讨论】:

      • 是的,Vue 团队似乎真的不希望人们拥有像 Vue 2 这样的全局属性。我什至尝试过执行 `setup() { getCurrentInstance().hello = 'abc'} 和对象被冻结(不可修改),所以我无法添加该属性
      猜你喜欢
      • 2020-12-16
      • 2020-12-05
      • 1970-01-01
      • 1970-01-01
      • 2021-10-27
      • 2021-07-06
      • 2022-08-10
      • 2021-05-26
      • 1970-01-01
      相关资源
      最近更新 更多