Vue.js可复用Tabs组件如何实现可自定义头部标题?
优化TabsWrapper组件的自定义头部标题实现
我通过教程实现了可复用Tabs组件,现在需要给TabsWrapper组件添加可自定义的主头部标题,让切换标签页时主头部能显示对应Tab的自定义标题。目前尝试提取Tab的headtitle属性来实现,但希望有更优方案。相关代码如下:
页面引入组件代码
<TabsWrapper> <Tab title="Tab 1" headtitle="主标题1">Hello 1</Tab> <Tab title="Tab 2" headtitle="主标题2">Hello 2</Tab> <Tab title="Tab 3">Hello 3</Tab> <!-- 未设置headtitle时可复用title --> <Tab title="Tab 4" headtitle="主标题4">Hello 4</Tab> </TabsWrapper>
TabsWrapper原有代码
<template> <div class="tabs"> <div class="tab_header"></div> <ul class="tabs_header"> <li v-for="title in tabTitles" :key="title" @click="selectedTitle = title" :class="{ selected: title === selectedTitle }" > {{ title }} </li> </ul> <slot /> </div> </template> <script> import { ref, provide } from 'vue'; export default { setup(props, { slots }) { const tabTitles = ref(slots.default().map(tab => tab.props.title)) const selectedTitle = ref(tabTitles.value[0]) provide("selectedTitle", selectedTitle) return { selectedTitle, tabTitles, } } } </script>
我尝试的实现代码
<template> <div class="tabs"> <div class="tab_header" v-for="headtitle in headTitles" :key="headtitle">{{headtitle}}</div> <ul class="tabs_header"> <li v-for="title in tabTitles" :key="title" @click="selectedTitle = title" :class="{ selected: title === selectedTitle }" > {{ title }} </li> </ul> <slot /> </div> </template> <script> import { ref, provide } from 'vue'; export default { setup(props, { slots }) { const tabTitles = ref(slots.default().map(tab => tab.props.title)) const headTitles = ref(slots.default().map(tab => tab.props.headtitle)) const selectedTitle = ref(tabTitles.value[0]) provide("selectedTitle", selectedTitle) return { selectedTitle, tabTitles, headTitles, } } } </script>
优化方案
当前尝试的代码会渲染所有Tab的headtitle,不符合“切换标签页时显示对应主标题”的需求。更合理的做法是将每个Tab的title和headtitle关联存储,通过选中状态动态切换主头部标题:
<template> <div class="tabs"> <!-- 动态显示当前选中Tab的主标题 --> <div class="tab_header">{{ currentHeadTitle }}</div> <ul class="tabs_header"> <li v-for="item in tabItems" :key="item.title" @click="selectedTitle = item.title" :class="{ selected: item.title === selectedTitle }" > {{ item.title }} </li> </ul> <slot /> </div> </template> <script> import { ref, computed, provide } from 'vue'; export default { setup(props, { slots }) { // 将每个Tab的title和headtitle整合为对象数组,关联存储 const tabItems = ref(slots.default().map(tab => ({ title: tab.props.title, // 未设置headtitle时,默认使用title作为主标题 headtitle: tab.props.headtitle || tab.props.title }))) const selectedTitle = ref(tabItems.value[0]?.title || '') // 计算当前选中Tab对应的主标题 const currentHeadTitle = computed(() => { const activeItem = tabItems.value.find(item => item.title === selectedTitle.value) return activeItem ? activeItem.headtitle : '' }) provide("selectedTitle", selectedTitle) return { selectedTitle, tabItems, currentHeadTitle } } } </script>
优化点说明
- 避免维护两个独立数组(
tabTitles和headTitles),减少数据不一致的风险 - 通过计算属性
currentHeadTitle动态获取当前选中Tab的主标题,无需手动遍历 - 增加默认值处理:当Tab未设置
headtitle时,自动复用title作为主标题 - 模板中无需循环渲染主标题,只显示当前选中项的对应内容
内容的提问来源于stack exchange,提问作者Akirambur
相关产品推荐
相关产品推荐

