Vue3项目中Bootstrap 5标签页点击后内容无法切换的解决
修复Vue3 + Bootstrap5标签页内容不切换的问题
问题根源很明确:NavBar组件和App组件各自维护了独立的activeTab状态,点击标签时只有NavBar的状态更新了,App里控制内容显示的activeTab完全没变化,所以内容一直停留在初始标签。
直接上修复方案:
1. 把状态统一到父组件(App.vue)
把activeTab的控制权交给App.vue,NavBar只负责触发切换事件,不维护自己的状态。
修改NavBar.vue
- 把
activeTab从data移到props里 - 点击标签时通过
$emit通知父组件切换状态 - 阻止a标签的默认跳转行为(避免页面滚动到锚点)
<template> <div id="navs" class="m-2"> <ul class="nav nav-tabs" role="tablist"> <li class="nav-item"> <a class="nav-link" :class="{ active: activeTab === 'web' }" @click.prevent="$emit('tab-change', 'web')" href="#web" ><font-awesome-icon icon="globe"/></a> </li> <li class="nav-item"> <a class="nav-link" :class="{ active: activeTab === 'flag' }" @click.prevent="$emit('tab-change', 'flag')" href="#flag" ><font-awesome-icon icon="flag"/></a> </li> <li class="nav-item"> <a class="nav-link" :class="{ active: activeTab === 'fb' }" @click.prevent="$emit('tab-change', 'fb')" href="#fb" ><font-awesome-icon :icon="{ prefix: 'fab', iconName: 'facebook' }"/></a> </li> <li class="nav-item"> <a class="nav-link" :class="{ active: activeTab === 'twitter' }" @click.prevent="$emit('tab-change', 'twitter')" href="#twitter" ><font-awesome-icon :icon="{ prefix: 'fab', iconName: 'square-x-twitter' }"/></a> </li> <li class="nav-item"> <a class="nav-link" :class="{ active: activeTab === 'yt' }" @click.prevent="$emit('tab-change', 'yt')" href="#yt" ><font-awesome-icon :icon="{ prefix: 'fab', iconName: 'youtube' }"/></a> </li> </ul> </div> </template> <script> export default { name: "NavBar", props: { activeTab: { type: String, required: true } } }; </script> <style scoped> /* Add your component-specific styles here */ </style>
修改App.vue
- 给NavBar组件绑定
activeTab属性,把自己的状态传过去 - 监听
tab-change事件,更新自己的activeTab - 补上fb、twitter、yt对应的tab-content(不然点击这些标签看不到内容)
<template> <div id="container"> <NavBar :activeTab="activeTab" @tab-change="activeTab = $event" /> <div class="tab-content"> <div id="web" class="container tab-pane" :class="{ active: activeTab === 'web' }" > <h3 class="text-danger">Web</h3> <BaseElements /> <chart></chart> </div> <div id="flag" class="container tab-pane" :class="{ active: activeTab === 'flag' }" > <h3 class="text-light">Country</h3> </div> <!-- 补上剩下的标签内容 --> <div id="fb" class="container tab-pane" :class="{ active: activeTab === 'fb' }" > <h3 class="text-light">Facebook</h3> </div> <div id="twitter" class="container tab-pane" :class="{ active: activeTab === 'twitter' }" > <h3 class="text-light">Twitter</h3> </div> <div id="yt" class="container tab-pane" :class="{ active: activeTab === 'yt' }" > <h3 class="text-light">Youtube</h3> </div> </div> </div> </template> <script> import "bootstrap/dist/css/bootstrap.min.css"; import NavBar from "./components/navBar.vue"; import BaseElements from "./components/BaseElements.vue"; import BarChart from "./components/BarChart"; export default { name: "App", components: { NavBar, BaseElements, chart: BarChart, }, data() { return { activeTab: "web", }; }, methods: { handler() { var args = arguments; for (var arg of args) { if (arg instanceof Function) { arg(); } } }, }, }; </script> <style> body { margin: 0; background-color: #002a53 !important; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } code { font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", monospace; } </style>
2. 额外优化(可选)
如果想直接用Bootstrap的原生JS功能,也可以不用Vue的状态管理,只需要给标签和内容加上正确的Bootstrap属性:
- 给a标签加
data-bs-toggle="tab"和data-bs-target="#xxx" - 给内容容器加
role="tabpanel"
这种方式不需要写Vue的状态和事件,但需要确保Bootstrap的JS已经引入(你已经安装了bootstrap和@popperjs/core,只需要在App.vue里导入bootstrap/dist/js/bootstrap.min.js)。不过这种方式和Vue的响应式结合起来可能不如第一种灵活,推荐用第一种Vue原生的状态管理方式。
内容的提问来源于stack exchange,提问作者nb_nb_nb
相关产品推荐
相关产品推荐

