Vue/Nuxt:如何定义一个全局方法,使所有组件都可以访问?

23

我只希望能够打电话。

{{ globalThing(0) }}

在模板中,无需在每个.vue文件中定义globalThing。

我尝试了各种插件配置(或者是混合?不确定Nuxt是否使用这个术语),但都无济于事。无论我做什么,globalThingthis.globalThing始终未定义。

在某些情况下,我甚至可以在Chrome中进行调试,看到this.globalThing确实被定义了...但代码仍然崩溃,这让我很难解释。

这是我的许多尝试之一,这次使用插件:

nuxt.config.js:

plugins: [
    {
        src: '~/plugins/global.js',
        mode: 'client'
    },
],

全局.js:

import Vue from 'vue';
Vue.prototype.globalFunction = arg => {
    console.log('arg', arg);
    return arg;
};

并且在.vue文件中的模板中:

        <div>gloabal test {{globalFunction('toto')}}</div>

并且...结果为:

TypeError _vm.globalFunction 不是一个函数


这里有一个不同的想法,使用Vuex store。

store/index.js:

export const actions = {
    globalThing(p) {
        return p + ' test';
    }
};

.vue文件模板: 测试结果:{{test('fafa')}}

.vue文件脚本:

import { mapActions } from 'vuex';

export default {

    methods: {
        ...mapActions({
            test: 'globalThing'
        }),
    }
};

结果是.........

测试结果:[object Promise]

好的,这次至少方法存在了。我很希望不必在每个组件中强制执行“import mapActions”等操作......但如果那真的是唯一的方法,那就无妨。

然而,由于此调用是异步的,我只得到一个Promise。当它完成时,Promise确实包含返回的值,但对我来说没有用处,因为我需要它从该方法中返回。


编辑

在客户端,“this”是未定义的,除非......它并不是!也就是说,

console.log('this', this); 

控制台输出显示为“undefined”,但 Chrome 的调试器声称,在此控制台日志之后,“this”正是它应该是的组件实例,this.$store也是如此!由于我自己都不相信自己的眼睛,所以在这里添加了一张截图作为证明。

just plain not possible


1
import Vue from 'vue'; Vue.prototype.globalThing = arg => { ... } 你需要这个吗? - talkhabi
尝试过了,没有起作用。 - Marc
插件是你正在寻找的东西。请查看Nuxt文档并重试。 如果还不行,请让我们以某种方式查看你的代码。 - Emīls Gulbis
是的,这正是我想的,但我已经尝试了整整一个下午使用这个插件功能,但我离我的目标还很远。已添加代码以反映您所描述的情况。 - Marc
你所指的文档是 https://nuxtjs.org/guide/plugins/ 吗?因为这里没有提到从模板中进行调用。然后有Vue插件文档,这里 https://vuejs.org/v2/guide/plugins.html ... 与Nuxt文档非常不同。我不知道...也许我会尝试按照Vue文档中描述的去做。 - Marc
3个回答

28

https://nuxtjs.org/guide/plugins/

Nuxt 在“向 $root 和 context 注入”部分进行了解释。

你必须将全局方法注入到 Vue 实例和上下文中。

例如,我们有一个 hello.js 文件。

在 plugins/hello.js 中:

export default (context, inject) => {
  const hello = (msg) => console.log(`Hello ${msg}!`)
  // Inject $hello(msg) in Vue, context and store.
  inject('hello', hello)
  // For Nuxt <= 2.12, also add 
  context.$hello = hello
}

然后在nuxt.config.js中添加此文件:

export default {
  plugins: ['~/plugins/hello.js']
}


19
  1. 使用 Nuxt 的 inject 将方法注入到任何地方
export default ({ app }, inject) => {
  inject('myInjectedFunction', (string) => console.log('That was easy!', string))
}
  1. 确保您访问该函数时使用$myInjectedFunction(注意$
  2. 确保将其添加到nuxt.config.js插件部分

如果其他方法都失败了,请将函数包装在对象中并注入对象,这样您的模板中就会有类似于$myWrapper.myFunction() 的东西 - 我们从插件中注入对象到各个地方,它们都可以正常工作(例如,在模板中的v-if中),所以我很确定它也可以从{{}}中使用。

例如,我们的analytics.js插件看起来是这样的:

import Vue from 'vue';
const analytics = {
    setAnalyticsUsersData(store) {...}
    ...
}

//this is to help Webstorm with autocomplete
Vue.prototype.$analytics = analytics;

export default ({app}, inject) => {
    inject('analytics', analytics);
}

然后被称为$analytics.setAnalyticsUsersData(...)

顺便提一下,我注意到了一些事情。你的插件处于客户端模式。如果你在通用模式下运行,你必须确保在 SSR 期间不会在任何地方使用此插件(和该函数)。如果它在模板中,则很可能实际上在 SSR 期间使用,并且因此未定义。将你的插件更改为同时在两种模式下运行。


好吧,那差不多可以了。插件函数实际上被找到并调用了,这是一个小奇迹,但现在在该函数中“this.$store”未定义。所以...似乎“this”不是它应该是的东西,即组件实例。找到存储实例总是一件特别麻烦的事情...为什么他们不只是将存储作为全局变量呢,我想我永远都不会明白。 哦,关于使插件在服务器端可用的好决定。那是问题的重要部分。 - Marc
所以这个兔子洞越来越奇怪了。在服务器上,“this”是未定义的,我想这很正常,反正我们在那里也没有$store,所以谁在乎呢。但是……在客户端,“this”也是未定义的,除了……它不是!也就是说,console.log('this',this);说“未定义”,但Chrome的调试器声称,在此控制台日志之后,“this”正是它应该是的,而且this.$store也是如此!我正在添加一个屏幕截图作为证明,因为我甚至不相信自己的眼睛。 - Marc
1
只有在组件创建后才能使用,因此取决于您尝试访问它的位置 - 例如,在beforeCreate钩子中,this将是未定义的。同样适用于各种Nuxt钩子。 也许您会发现我这一系列文章有所帮助?https://dev.to/lilianaziolek/understanding-nuxt-vue-hooks-and-lifecycle-part-1-48lc - Lili
在这种特定情况下,您可以通过将其添加到从Nuxt上下文中提取的store来访问它,即:export default ({ app, store }, inject) - Lili
此外,不要相信在 Devtools 上下文中执行的命令 - 它们可能在您想象的上下文中运行。请相信日志记录语句。 - Lili
这个“如果在模板中,它很可能在 SSR 过程中实际被使用,因此是未定义的。”真的救了我的一天。 - chick3n0x07CC

-1

这将是使用Vuex和Nuxt的方法:

// store/index.js

export const state = () => ({
    globalThing: ''
})

export const mutations = {
    setGlobalThing (state, value) {
        state.globalThing = value
    }
}


// .vue file script

export default {
    created() {
        this.$store.commit('setGlobalThing', 'hello')
    },
};



// .vue file template

{{ this.$store.state.globalThing }}


1
不行。这种方式无法像问题中展示的那样向globalThing传递参数:{{ globalFunction('toto') }}。 - Marc

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接