<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Tab Switcher Example</title>
<script src="vue.js"></script>
<style>
.tab-label {
background: #ccc;
padding: 2px 5px;
line-height: 30px;
text-align: center;
cursor: pointer;
margin-right: 4px;
}
.tab-label.active {
color: #fff;
background: green;
}
</style>
</head>
<body>
<div id="app">
<component :is="currentView"></component>
<span
v-for="(tab, index) in tabs"
:key="index"
:class="{ active: selectedIndex === index }"
class="tab-label"
@click="switchTab(index)"
>
{{ tab.label }}
</span>
</div>
<script>
const PanelA = { template: '<div>Content of Tab A</div>' };
const PanelB = { template: '<div>Content of Tab B</div>' };
const PanelC = { template: '<div>Content of Tab C</div>' };
new Vue({
el: '#app',
data() {
return {
currentView: 'PanelA',
selectedIndex: 0,
tabs: [
{ label: 'Tab 1', component: 'PanelA' },
{ label: 'Tab 2', component: 'PanelB' },
{ label: 'Tab 3', component: 'PanelC' }
]
};
},
methods: {
switchTab(index) {
this.selectedIndex = index;
this.currentView = this.tabs[index].component;
}
},
components: {
PanelA,
PanelB,
PanelC
}
});
</script>
</body>
</html>
This implementation uses Vue 2’s dynamic component feature with :is to render the active tab content. The tab labels are generated via v-for, binding click events to update both the selected index and the current component.
Key points:
- The
:classdirective toggles theactiveclass based onselectedIndex, avoiding manual array mutation. - Direct assignment too
selectedIndexandcurrentViewensures reactivity without needingVue.setor$set, since these properties are declared in the initialdata()object. - Each tab entry stores its associated component name, enabling clean mapping between UI and dynamic content.
This approach simplifies state management and avoids unnecessary complexity while maintaining full reactivity.