效果:
快来学习:
Vue 3 Composition API 和
script setup
语法
- Composition API:Vue 3 引入的 Composition API 相比 Vue 2 的 Options API 提供了更灵活的代码组织方式。使用
setup
函数,可以将组件的所有功能和逻辑集中在一起,方便复用。script setup
语法:Vue 3 的<script setup>
是 Composition API 的简化写法,将setup
函数的代码直接编写在<script setup>
中,自动将定义的变量和方法暴露给模板。响应式状态管理
ref
:ref
用于定义单一响应式变量,当变量改变时,Vue 会自动更新模板。示例中的tabCount
和activeTabId
使用ref
定义。reactive
:reactive
用于定义复杂的数据结构,如对象或数组。示例中的tabs
使用reactive
定义,管理页签数据,数组变化时页面会自动更新。页面渲染和模板指令
v-for
:Vue 的v-for
指令用于循环渲染数组的每个元素。这里使用v-for="tab in tabs"
循环渲染所有页签和内容。- 动态类绑定:
v-bind:class
或简写:class
用于动态绑定类名,['tab', { active: activeTabId === tab.id }]
实现了激活状态的切换。- 事件处理:使用
@click
绑定点击事件,点击时触发相应的激活或关闭操作。Vue 提供的事件修饰符.stop
可以阻止事件冒泡,防止触发父级元素的点击事件。事件冒泡与
@click.stop
- 事件冒泡:HTML 中,点击事件会逐级向上传递到父级元素。这种行为在需要精准触发特定操作时会带来困扰。
@click.stop
修饰符:Vue 提供.stop
修饰符阻止事件冒泡,确保关闭按钮仅触发关闭操作而不会激活页签。Scoped CSS
- Scoped 样式:
<style scoped>
限制样式只作用于当前组件,防止影响其他组件,保证了组件的样式独立性。
代码:
<template>
<!-- 页签容器 -->
<div class="tabs-container">
<!-- 页签列表 -->
<div class="tabs">
<!-- 使用 v-for 循环渲染每一个页签 -->
<div v-for="tab in tabs" :key="tab.id" :class="['tab', { active: activeTabId === tab.id }]"
@click="activateTab(tab.id)">
{{ tab.label }}
<!-- 关闭按钮,阻止事件冒泡以防触发 activateTab -->
<span class="close-btn" @click.stop="closeTab(tab.id)">x</span>
</div>
</div>
<!-- 添加新页签的按钮 -->
<button style="width: 50px; height: 30px;" @click="addTab">+</button>
</div>
<!-- 页签内容容器 -->
<div class="content-container">
<!-- 循环渲染每个页签对应的内容区域 -->
<div v-for="tab in tabs" :key="tab.id" :class="['tab-content', { active: activeTabId === tab.id }]">
{{ tab.content }}
</div>
</div>
</template>
<script setup>
import { reactive, ref } from 'vue'
// 初始化页签计数器,用于给每个新页签分配唯一 ID
let tabCount = ref(0)
// 定义一个响应式数组,用于存储所有的页签信息
const tabs = reactive([])
// 定义当前激活页签的 ID
const activeTabId = ref(null)
// 添加新页签的函数
function addTab () {
tabCount.value++ // 页签计数加一
const newTab = {
id: tabCount.value, // 分配唯一 ID
label: `页签 ${tabCount.value}`, // 页签的标签名称
content: `这是页签 ${tabCount.value} 的内容` // 页签的内容
}
tabs.push(newTab) // 将新页签加入页签数组
activateTab(newTab.id) // 激活新添加的页签
}
// 激活指定页签的函数
function activateTab (tabId) {
activeTabId.value = tabId // 更新当前激活的页签 ID
}
// 关闭指定页签的函数
function closeTab (tabId) {
// 找到要关闭的页签的索引
const index = tabs.findIndex((tab) => tab.id === tabId)
if (index !== -1) {
tabs.splice(index, 1) // 从数组中移除该页签
// 如果关闭的是当前激活的页签
if (activeTabId.value === tabId && tabs.length > 0) {
activeTabId.value = tabs[0].id // 激活第一个页签
} else if (tabs.length === 0) {
activeTabId.value = null // 如果没有页签,重置 activeTabId 为 null
}
}
}
</script>
<style scoped>
/* 样式 */
.tabs {
display: flex;
align-items: center;
margin-bottom: 10px;
}
.tabs-container {
display: flex;
align-items: center;
justify-content: start;
}
.tab {
position: relative;
padding: 10px 20px;
margin-right: 5px;
background-color: #eee;
cursor: pointer;
border-radius: 5px;
}
.tab.active {
background-color: #ddd;
/* 激活状态的页签背景色 */
}
.close-btn {
position: absolute;
right: 5px;
top: 5px;
font-size: 14px;
cursor: pointer;
color: red;
}
.tab-content {
display: none;
/* 默认隐藏页签内容 */
}
.tab-content.active {
display: block;
/* 仅激活的页签内容显示 */
height: 200px;
width: 300px;
color: #fff;
background-color: green;
}
</style>
标签:vue,tabs,value,activeTabId,Vue,tab,ref
From: https://blog.csdn.net/m0_72030584/article/details/143626496