京东App头部栏切换效果
效果图

父组件
<template>
<view class="index">
<view class="tabs_box">
<Tabs :list="tabList" />
</view>
</view>
</template>
<script setup lang="ts">
import Tabs from '@/components/Tabs/Tabs.vue'
const tabList = [
{ label: '首页', id: '0' },
{ label: '小时达', id: '1' },
{ label: '终于完成了', id: '2' }
]
</script>
<style scoped lang="scss">
.index {
width: 100%;
min-height: 100vh;
background-color: antiquewhite;
.tabs_box {
display: flex;
justify-content: center;
align-items: center;
padding-top: 100upx;
}
}
</style>
子组件
<template>
<view class="tabs">
<view
:style="{ width: item.w + 'rpx' }"
:class="['tabs_item', { active: item.id === tabActive }]"
v-for="item in tabList"
:key="item.id"
@click="tabClick(item.id)"
>
{{ item.label }}
</view>
<view class="indicator" :style="{ width: tabList[tabActive].w + 'rpx', transform: `translateX(${tabActiveTranslateX})` }"></view>
</view>
</template>
<script setup lang="ts">
import { ref, watch } from 'vue'
interface ITabsProps {
list: any[]
}
interface ITabList {
id: string
w: string
label: string
}
const props = defineProps<ITabsProps>()
const tabList: ITabList[] | any = ref([])
const tabActive = ref('0')
const tabActiveTranslateX = ref('0rpx')
watch(
() => props.list,
(newVal) => {
tabList.value = newVal.map((i) => {
return {
...i,
w: i.label.length * 28 + 40
}
})
},
{
immediate: true
}
)
const tabClick = (id: string) => {
if (id === tabActive.value) return
if (id === '0') {
tabActive.value = id
return (tabActiveTranslateX.value = '0rpx')
}
if (Number(id) > Number(tabActive.value)) {
let number = 0
tabList.value.forEach((item: any, index: number) => {
if (index < Number(id)) {
number += item.w
}
})
tabActiveTranslateX.value = number + 'rpx'
}
if (Number(id) < Number(tabActive.value)) {
tabActiveTranslateX.value = tabList.value[Number(id) - 1].w + 'rpx'
}
tabActive.value = id
}
</script>
<style scoped lang="scss">
.tabs {
padding: 0 10upx;
background-color: #e90039;
height: 80upx;
display: flex;
justify-content: center;
align-items: center;
border-radius: 80upx;
font-size: 28upx;
position: relative;
.tabs_item {
display: flex;
align-items: center;
justify-content: center;
height: 60upx;
color: #fff;
line-height: 60upx;
border-radius: 60upx;
}
.active {
color: #f82b19;
z-index: 99;
}
.indicator {
position: absolute;
left: 10upx;
height: 60upx;
border-radius: 60upx;
background-color: #fbd5de;
transition: 0.5s;
}
}
</style>