vue-i18n因appContext丢失而无法使用的问题

最近,在使用vue-i18n插件的时候遇到了这样的问题:

image-20250111120023834

前者是在Chrome浏览器上,后者是在FireFox浏览器上。

报错的直接诱因是在某个组件上直接引入了vue-i18n并使用了useI18n

import { useI18n } from "vue-i18n"
const { t } = useI18n()

甚至导致整个项目都白屏无法渲染。

在排查问题之后,我发现这是由于使用vue-i18n的那个组件中的appContextappnull导致的。

image-20250111120230486

因为vue-i18n将自己的功能函数挂载在app这个全局上下文中,而这个组件是使用createVNode创建并渲染在body上的,因为某些原因就丢失了appContextapp,因此vue-i18n找不到自己的SYMBOL,最终导致报错。

解决方法

解决方法也很简单,直接在createVNode里调用const { appContext } = getCurrentInstance()!,再将父组件的appContext赋值给它就可以了。

const { appContext } = getCurrentInstance()!
const vm = createVNode(component, props);
vm.appContext = appContext;

或者还有另一种解法,写一个vue插件,全局注入appContext。

import { App, inject, AppContext } from "vue";

interface ProvideAppPluginOptions {
  globalPropertyName?: string; // 全局属性名
  onInstall?: (appContext: AppContext) => void; // 安装插件时的回调
}

const key = "__CURRENT_APP_CONTEXT__";

export const ProvideAppPlugin = {
  install(app: App, options: ProvideAppPluginOptions = {}) {
    if (!app || typeof app.provide !== "function") {
      throw new Error("ProvideAppPlugin requires a valid Vue app instance.");
    }

    // 获取完整的 appContext
    const appContext = app._context;

    // 注入 appContext
    app.provide(key, appContext);

    // 可选:设置全局属性
    if (options.globalPropertyName) {
      app.config.globalProperties[options.globalPropertyName] = appContext;
    }

    // 可选:执行回调
    if (options.onInstall) {
      options.onInstall(appContext);
    }
  },
};

// 获取当前 appContext
export function useCurrentAppContext(): AppContext {
  const appContext = inject<AppContext>(key);
  if (!appContext) {
    throw new Error(
      "useCurrentAppContext must be used within a Vue component where ProvideAppPlugin is installed."
    );
  }
  return appContext;
}

// 获取当前 app 实例(从 appContext 中提取)
export function useCurrentApp(): App {
  const appContext = useCurrentAppContext();
  return appContext.app;
}

然后直接调用获取:

import { useCurrentAppContext } from '@/plugins/ProvideAppPlugin';
const vm = createVNode(component, props);
const appContext = useCurrentAppContext();
if (appContext) {
	vm.appContext = appContext;
}