未来我们在使用时:
<k-tabs v-model="activeTab">
<k-tab id="tab1" title="Tab1">Tab1 Content</k-tab>
<k-tab id="tab2" title="Tab1">Tab2 Content</k-tab>
<k-tab id="tab3" title="Tab1">Tab3 Content</k-tab>
</k-tabs>
所以我们需要一个activeTab变量,为一个字符串,它决定了标签显示的内容是什么。
对于tabs组件,我们需要实现组件的双向绑定,有一个modelValue的属性,还有事件updatae:modelValue,还有插槽。
import {defineComponent} from 'vue';
export default defineComponent ({
name: 'KTabs',
props: {
modelValue: {
type: String,
}
},
emits: ['updatae:modelValue'],
setup(props, {slots}) {
const tabsData = ref([])
provide('tabs-data', tabsData)
// 激活id
const activeTab = ref(props.modelValue)
provide('active-tab', activeTab)
const changeTab = (tabId: string) => {
activeTab.value = tabId
}
return () =>
<div class={'k-tabs'}>
{/* 导航页签 */}
<ul className='k-tabs__nav>
{tabsData.value.map(tab => <li onClick={() => changeTab(tab.id)} class={tab.id === activeTab.value ? 'active' : ''}>{tab.title}</li>)}
</ul>
{/* 内容区 */}
{slots.default?.()}
</div>
}
})
对于tab组件,有两个属性和一个默认插槽,tab组件需要控制内容的显示与隐藏,只需要上层提供激活状态IdactiveTab就可以进行比较控制。
import {defineComponent} from 'vue';
export default defineComponent ({
name: 'KTab',
props: {
id: {
type: String,
required: true
},
title: {
type: String,
required: true
}
},
setup(props, {slots}) {
// 获取当前激活项
const activeTab = inject('active-tab') as Ref<string>
// 获取tabsData,并将自身数据加入其中
inject('tabs-data') as Ref<
Array<{id: string; title: string }>
>
tabsData.value.push({
id: props.id,
title: props.title
})
return () => (
<>
{props.id === activeTab.value && (
<div class={'k-tab'}>{slots.default?.()}</div>)}
</>
)
}
})
.k-tabs{
display: flex;
flex-direction: column;
ul.k-tabs__nav {
list-style: none;
display: inline-flex;
margin: 0;
padding: 0;
border-bottom: 2px solid #e4e7ed;
cursor: pointer;
li {
margin-left: 32pxp;
margin-bottom: -2px;
color: #303133;
padding-bottom: 4px;
}
&:first-child {
margin-left: 0;
}
&.active {
font-weight: 700;
border-bottom: 2px solid #409eff;
color: #409eff;
svg {
fill: #409eff;
}
}
&:hover: {
color: #409eff;
svg {
fill: #409eff;
}
}
}
}