tab栏实现
TabControl.vue
<template>
<div class="TabControl">
<ul>
<li v-for="(item, index) in tabsTitle" :key="index" @click="handleClikc(index)"
:class="{ active: index === curIndex }">
{{ item }}</li>
</ul>
</div>
</template>
<script setup lang="ts">
import { ref, reactive } from 'vue'
const props = defineProps({
tabsTitle: {
type: Array,
default: () => []
}
})
// 抛出自定义事件
const emits = defineEmits(['clickTab'])
// 当前下标
let curIndex = ref(0)
function handleClikc(index) {
curIndex.value = index
emits('clickTab', index)
}
</script>
<style scoped lang="less">
.TabControl {
ul {
display: flex;
overflow-y: auto;
li {
padding: 4px 10px;
}
}
}
.active {
border-bottom: 2px solid var(--primary-color);
}
</style>
点击tab滚动到指定位置
- 给tab栏组件传入tab数组
- 获取各个组件实例
- 点击tab,监听scrollTop
// 1.滚动到300px 显示tab栏
const { isBottom, scrollTop, clientHeight, scrollHeight } = useScroll()
const showTabs = computed(() => {
return scrollTop.value > 300
})
// 2.getSectionRef获取绑定了ref属性的组件的根元素
// value为绑定了ref属性的proxy对象
let sectionEls = []
function getSectionRef(value) {
if (!value) return
// value.$el 获取当前组件的根元素
sectionEls.push(value.$el)
sectionEls = [...new Set(sectionEls)]
}
// 3.点击tab 滑动到对应位置
// scrollTo为DOM相关API
function clickTab(index) {
window.scrollTo({
top: sectionEls[index].offsetTop,
behavior: 'smooth'
});
}
滚动到指定位置tab栏切换
// 监听页面滚动 匹配到对应tab的下标
// 监听scrollTop变化,找到第一个offset(当scrollTop>=某个tab所对应的offset时),保存该offset对应的tab的下标index
// 例如 scrollTop=600 offsetArr=[100,300,800,1000] 800>=600 则保存300所对应的下标1
// scrollTop=6000 返回下标offsetArr.length-1
// scrollTop=6 返回下标-1
let tabRef = ref()
watch(scrollTop, (newVal) => {
// 遍历各个位置的范围区间
const valueArr = sectionEls.map(el => el.offsetTop).slice(0, sectionEls.length)
let index = valueArr.length - 1
for (let i = 0; i < valueArr.length; i++) {
// 26为tab栏高度 避免遮挡
if (valueArr[i] >= newVal + 26) {
index = i - 1
break
}
}
// 修改tab组件的当前下标
tabRef.value.curIndex = index
})