如何在asyncData中访问模板的this.$el以合并数据库i18n翻译?
问题本质拆解
首先要明确两个根本性的时机矛盾,会让你直接在asyncData中访问this.$el的思路完全走不通:
asyncData的执行时机远早于组件挂载:不管是服务端渲染阶段,还是客户端路由跳转时的首次执行,此时组件实例还没初始化完成,既没有绑定可用的this上下文,更没有生成挂载后才会存在的$elDOM引用,强行访问只会拿到undefined- 就算你能拿到
$el,DOM里存的也是翻译完成后的最终文本,根本没法反向提取出数据库里对应的翻译key,后续的请求逻辑根本没法跑通
可落地的实现方案
方案1:预先声明翻译依赖(最稳定可控)
完全抛弃依赖$el收集翻译条目的思路,直接在组件层面明确定义当前页面所需的翻译key列表,在asyncData中通过上下文获取i18n实例,完成请求和翻译合并的全流程。这个方案全程在页面首次渲染前执行,不会出现翻译闪烁的问题。
示例代码:
// 模块级定义当前页面依赖的翻译key,不需要依赖组件实例或DOM const pageTranslationKeys = ['common.confirm', 'home.banner.title', 'user.profile.email'] export default { // 把key列表挂到组件选项上,方便后续其他逻辑复用 translationDependencies: pageTranslationKeys, async asyncData(context) { // 从全局上下文直接拿到i18n实例,不需要通过this访问 const i18n = context.app.i18n const currentLocale = i18n.locale // 携带当前语言、所需的key列表,向服务端请求对应翻译数据 const translatedMessages = await context.$axios.$get('/api/translation/fetch', { params: { locale: currentLocale, keys: pageTranslationKeys } }) // 将请求到的翻译数据合并到全局i18n实例 i18n.mergeLocaleMessage(currentLocale, translatedMessages) return { // 其他页面业务数据 } } }
方案2:自动收集翻译key(无需手动维护列表)
如果不想手动编写每个页面的key列表,可以通过方法拦截的方式在执行阶段自动收集所有用到的翻译key,全程不需要依赖DOM或$el:
- 在每次请求的初始化阶段,给当前上下文挂载一个空的集合,用来存储收集到的翻译key
- 重写i18n实例的
t方法,在原有逻辑外层增加拦截:每次调用t(key)时,将对应的key存入当前上下文的集合中 - 从请求进入、到
asyncData执行完成的全流程中,所有通过t方法使用的翻译key都会被自动收集 - 待
asyncData内的业务逻辑执行完成后,使用收集到的key集合向服务端请求对应翻译数据,执行mergeLocaleMessage完成合并
这个方案完全和DOM渲染流程解耦,既适配SSR场景,也适配客户端路由跳转的场景。
常见避坑点
- 不要把翻译加载逻辑放到
mounted、beforeMount这类挂载钩子中,这类钩子执行时DOM已经完成首次渲染,会先显示原始的翻译key字符串,等请求返回后再替换为真实翻译,出现明显的页面闪烁 - 不要尝试通过正则匹配DOM文本的方式提取翻译key,这种方式不仅效率低,还会把页面上的普通文本误识别成翻译key,出错率极高
内容的提问来源于stack exchange,提问作者Vladimir Golub
相关产品推荐
相关产品推荐

