Vue3中如何在其他组件调用计算属性作为标签文本?
我采用标签页式界面减少API调用,循环渲染标签时图标显示正常,但翻译文本无法展示。翻译文本是子组件的computed属性,想将该计算属性作为标签页的标签文本,请问该如何实现?
相关组件代码如下:
标签组件代码
<ul class="nav nav-tabs nav-fill nav-icons" id="tabsWithIcons" role="tablist"> <li class="nav-item" role="presentation" v-for="(tabObj, tab, index) in tabs" :key="index" :class="{ active: currentTab === tab }" @click="currentTab = tab"> <button class="nav-link justify-content-center" :class="[{ active: currentTab === tab }]" id="subsite-tab" data-bs-toggle="tab" data-bs-target="#subsites-tab-pane" type="button" role="tab" aria-controls="subsites-tab-pane" aria-selected="true"> <BootstrapIcon :icon="tabObj.tabIcon" /> <span>{{ tabObj.translation }}</span> </button> </li> </ul> <div class="tab-content my-4" id="myTabContent"> <div class="tab-pane fade show active" id="subsites-tab-pane" role="tabpanel" aria-labelledby="subsites-tab" tabindex="0"> <component :is="tabs[currentTab]"></component> </div> </div> <script setup> import Home from '@/views/Home' import Contact from '@/views/Contact' import AboutMe from '@/views/AboutMe' import { ref } from 'vue' const currentTab = ref('Home') const tabs = { Home, Contact, AboutMe, } </script>
About Me组件代码
<template> <div class="row"> <div class="col"> <Subtitle :title="$t('basicnavigation.tabs.aboutme')" /> </div> </div> <div class="row"> <div class="col"> content of component </div> </div> </template> <script setup> import Subtitle from '@/components/Titles/Subtitle.vue' import { ref } from 'vue' // ... some refs.. </script> <script> export default { computed: { translation() { return this.$t('basicnavigation.tabs.aboutme') }, }, tabIcon: 'person-fill', } </script>
尝试修改后出现错误:TypeError: Cannot read properties of undefined (reading 'translate')
核心问题:你直接访问的是组件的定义对象,而非组件实例,因此无法获取实例上的computed属性(translation),也无法调用依赖实例上下文的$t方法。
方案1:统一维护标签元数据(推荐)
将每个标签的翻译键、图标等信息统一放在标签页组件中,利用当前组件的$t方法直接生成文本,无需依赖子组件实例:
- 修改标签页组件的
<script setup>部分:
<script setup> import Home from '@/views/Home' import Contact from '@/views/Contact' import AboutMe from '@/views/AboutMe' import { ref } from 'vue' const currentTab = ref('Home') // 统一维护标签的组件、翻译键、图标 const tabs = [ { name: 'Home', component: Home, translationKey: 'basicnavigation.tabs.home', tabIcon: 'house-fill' }, { name: 'Contact', component: Contact, translationKey: 'basicnavigation.tabs.contact', tabIcon: 'envelope-fill' }, { name: 'AboutMe', component: AboutMe, translationKey: 'basicnavigation.tabs.aboutme', tabIcon: 'person-fill' } ] </script>
- 修改模板的循环逻辑:
<ul class="nav nav-tabs nav-fill nav-icons" id="tabsWithIcons" role="tablist"> <li class="nav-item" role="presentation" v-for="(tabObj, index) in tabs" :key="index" :class="{ active: currentTab === tabObj.name }" @click="currentTab = tabObj.name"> <button class="nav-link justify-content-center" :class="[{ active: currentTab === tabObj.name }]" id="subsite-tab" data-bs-toggle="tab" data-bs-target="#subsites-tab-pane" type="button" role="tab" aria-controls="subsites-tab-pane" aria-selected="true"> <BootstrapIcon :icon="tabObj.tabIcon" /> <span>{{ $t(tabObj.translationKey) }}</span> </button> </li> </ul> <div class="tab-content my-4" id="myTabContent"> <div class="tab-pane fade show active" id="subsites-tab-pane" role="tabpanel" aria-labelledby="subsites-tab" tabindex="0"> <component :is="tabs.find(tab => tab.name === currentTab)?.component"></component> </div> </div>
这种方式逻辑集中,便于统一管理标签展示信息,无需修改子组件。
方案2:通过组件实例获取翻译(不推荐)
若一定要从子组件获取翻译,需要先创建组件实例,但会增加复杂度,且不符合Vue组件设计逻辑。由于computed属性依赖组件实例的上下文(如this.$t),直接调用组件定义的computed方法会因上下文缺失报错,因此不推荐此方案。
你之前的代码中,tabs对象存储的是组件的构造函数/定义对象,而非组件实例。tabObj.translation试图访问组件定义上的属性,但translation是实例的computed属性,仅在组件实例化后存在;同时this.$t依赖VueI18n注入的实例上下文,在组件定义外调用会导致this指向错误,从而出现TypeError: Cannot read properties of undefined (reading 'translate')。
内容的提问来源于stack exchange,提问作者R-b-n

