在tab上定位一个slider,每次点击的时候获取当前active的tab-item序号,从而获取到其相对于父元素的水平距离,然后把这个距离更新到slider的left属性上。
代码存档↓
<template>
<!-- tab组件封装 -->
<div class="tab" style="margin-top: 10px;" >
<div
class="tab-item" v-for="(item, index) in props.tabData" :key="index"
@click="handleTabChange(index)"
:ref="el => {if(el)tabs[index] = el}"
>
{{ item.label }}
</div>
<div class="slider" :style="`left: ${data.sliderPositionX}px`">{{ data.activeLabel }}</div>
</div>
</template>
<script setup>
import {onMounted, reactive, ref} from 'vue'
//父组件传递来的tab信息
const props = defineProps({
tabData:{
type:Object,
validator: (value) => {
return value.hasOwnProperty('label') && value.label !== ''
}
}
})
const emit = defineEmits(['returnCurrentIndex'])
const data = reactive({
current: 1, //当前被选中的tab-item序号
sliderPositionX: 0, //slider X轴方向位置
windowWidth: window.innerWidth,
activeLabel:''
})
const tabs = ref([])
//更改slider的位置
function updateSliderPosition(){
let activeTab = tabs.value[data.current - 1]
data.sliderPositionX = activeTab.offsetLeft
data.activeLabel = props.tabData[data.current - 1].label
console.log('tab', data.sliderPositionX)
}
function handleTabChange(index){
data.current = index + 1
//向父组件返回当前active tab的序号 方便对页面更新
emit('returnCurrentIndex', data.current)
updateSliderPosition()
}
onMounted(() => {
updateSliderPosition()
window.addEventListener('resize', () => updateSliderPosition());
})
</script>
<style scoped lang="scss">
.tab{
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
margin-bottom: 10px;
position: relative;
.tab-item{
background-color: #353945;
border: 1px solid #B1B5C3;
color: #B1B5C3;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
font-size: 14px;
padding: 8px 16px;
box-sizing: border-box;
width: 95px;
height: 40px;
margin: 0;
}
.tab-item:first-child{
border-radius: 2px 0 0 2px;
}
.tab-item:last-child{
border-radius: 0 2px 2px 0;
}
.slider{
position: absolute;
top: 0;
width: 95px;
height: 40px;
transition: left 0.5s;
box-sizing: border-box;
background: linear-gradient(to right, #F4A58A, #ED6B4E);
color:#000;
border: 1px solid transparent;
display: flex;
align-items: center;
justify-content: center;
}
}
</style>