Vue.js中基于JSON数据动态填充Tabs的问题求助
动态生成Tab点击后始终显示第一个内容的问题解决
问题描述
我正在开发一个小型项目,需要基于本地.json文件的数据动态生成Tabs。目前Tab标题已正常显示,但点击任意Tab时,始终只展示第一个数据索引对应的内容。我尝试过遍历数据等方法,但都没有解决问题,希望能得到帮助。注:这是我第一次使用Vue.js,我知道Vue本身有更简便的实现方式,但现阶段更倾向于使用Vanilla JS,且因需求动态性未使用Tab ID。
当前代码
HTML(Vue模板)
<template> <section class="tab__container"> <div class="tab__sidebar"> <button class="tab__button" v-for="data in data" :key="data.title">{{ data.title }}</button> </div> <div class="tab__content" v-for="data in data" :key="data.content"> <p v-html="data.content"></p> </div> </section>
Vue组件脚本
import data from '../assets/data.json' export default { props: ['title', 'content'], data() { return { data: data } } }
CSS样式
.tab__container { display: none; } @media (min-width: 769px) { .tab__container { display: flex; border: 1px solid #d2d2d2; } .tab__sidebar { flex-direction: row; width: 125px; flex-shrink: 0; background: #cccccc; } .tab__button { display: block; padding: 10px; background: #eeeeee; border: none; width: 100%; outline: none; cursor: pointer; } .tab__button:active { background: #dddddd; } .tab__button:not(:last-of-type) { border-bottom: 1px solid #cccccc; } .tab__button.is__active { font-weight: bold; border-right: 2px solid #009879; background: #dddddd; } .tab__content { padding: 20px; font-size: 18px; display: none; } .tab__content.is__active { display: block; } }
Vanilla JS代码
document.querySelectorAll(".tab__button").forEach(button => { button.addEventListener("click", () => { var sidebar = button.parentElement; var tabContainer = sidebar.parentElement; var tabToActivate = tabContainer.querySelector(".tab__content"); sidebar.querySelectorAll(".tab__button").forEach(button => { button.classList.remove("is__active"); }); tabContainer.querySelectorAll(".tab__content").forEach(tab => { tab.classList.remove("is__active"); }); button.classList.add("is__active"); tabToActivate.classList.add("is__active"); }); });
JSON数据
[ { "title": "Section 1", "content": "<p>Maecenas nec semper ante, pellentesque posuere lorem. Nullam ipsum massa, consequat eget urna ut, pulvinar dignissim lorem. Nulla facilisi. Nam mattis eleifend metus. Fusce at commodo lorem. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Phasellus pellentesque elit sem, vel blandit posuere.</p>" }, { "title": "Section 2", "content": "<p>Mauris a orci sodales, scelerisque velit vitae, gravida nisl. Ut non laoreet eros, vel laoreet nisi. Praesent sed dolor dui. Proin non fringilla quam. Aliquam erat volutpat. Vestibulum vel arcu semper, lobortis turpis ac, ultricies nisi. Praesent id.</p>" }, { "title": "Section 3", "content": "<p>Sed elementum sapien ut sapien imperdiet, eu venenatis enim rhoncus. Praesent euismod tincidunt rhoncus. Duis cras amet:</p><ul><li>List item one</li><li>List item two</li><li>List item three</li></ul>" }, { "title": "Section 4", "content": "<p>Cras dictum. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Aenean lacinia mauris vel est.</p><p>Suspendisse eu nisl. Nullam ut libero. Integer dignissim consequat lectus. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos.</p>" } ]
问题原因
你的JS代码中,tabContainer.querySelector(".tab__content")只会返回匹配到的第一个.tab__content元素,所以无论点击哪个按钮,都会激活第一个内容块,这就是问题所在。
解决方案
修改JS代码,获取当前点击按钮在侧边栏中的索引,然后找到对应索引的内容块进行激活。同时添加初始化逻辑,默认激活第一个Tab:
// 初始化激活第一个Tab const tabContainer = document.querySelector(".tab__container"); const firstButton = tabContainer.querySelector(".tab__button"); const firstContent = tabContainer.querySelector(".tab__content"); firstButton.classList.add("is__active"); firstContent.classList.add("is__active"); // 绑定点击事件 document.querySelectorAll(".tab__button").forEach(button => { button.addEventListener("click", () => { const sidebar = button.parentElement; const tabContainer = sidebar.parentElement; // 获取当前按钮的索引 const buttonIndex = Array.from(sidebar.children).indexOf(button); // 获取对应索引的内容块 const tabToActivate = tabContainer.querySelectorAll(".tab__content")[buttonIndex]; // 移除所有激活状态 sidebar.querySelectorAll(".tab__button").forEach(btn => btn.classList.remove("is__active")); tabContainer.querySelectorAll(".tab__content").forEach(tab => tab.classList.remove("is__active")); // 激活当前按钮和对应内容 button.classList.add("is__active"); tabToActivate.classList.add("is__active"); }); });
说明
Array.from(sidebar.children).indexOf(button)将侧边栏的子元素(按钮)转为数组,然后获取当前点击按钮的索引。- 通过索引
buttonIndex从所有内容块中找到对应的tab__content元素,确保按钮和内容一一对应。 - 初始化部分保证页面加载时第一个Tab处于激活状态,符合常规交互逻辑。
内容的提问来源于stack exchange,提问作者moffitt
相关产品推荐
相关产品推荐

