vue3 手写tab栏的滑动效果

本文介绍了如何使用Vue.js开发一个动态的tab组件,当用户点击tab时,计算并更新slider的位置,使其跟随激活的tab-item的水平距离。作者展示了相关的代码片段和事件处理逻辑。
摘要由CSDN通过智能技术生成

在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>

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值