uniapp中scrollview配合swiper实现一个简单的tab标签页
·
<template>
<view class="tab-container">
<!-- Tab 标签滚动容器 -->
<scroll-view scroll-x="true" class="tab-scroll" scroll-with-animation="true">
<view class="tab-list">
<view
v-for="(item, index) in tabs"
:key="index"
class="tab-item"
:class="{ active: currentIndex === index }"
@click="changeTab(index)"
>
{{ item.name }}
</view>
</view>
</scroll-view>
<!-- 内容区域 -->
<swiper
:current="currentIndex"
class="swiper-content"
@change="onSwiperChange"
:duration="300"
scroll-x="true"
>
<swiper-item v-for="(item, index) in tabs" :key="index">
<view class="swiper-item-content">
<!-- 内容区域的具体内容 -->
<view>{{ item.name }} Content</view>
</view>
</swiper-item>
</swiper>
</view>
</template>
<script lang="ts">
import { ref } from 'vue';
export default {
setup() {
const tabs = ref([
{ name: 'Tab 1' },
{ name: 'Tab 2' },
{ name: 'Tab 3' },
{ name: 'Tab 4' },
// { name: 'Tab 5' },
// { name: 'Tab 6' },
// { name: 'Tab 7' },
// { name: 'Tab 8' },
// { name: 'Tab 9' },
// ... 更多 Tab
]);
const currentIndex = ref(0);
const changeTab = (index: number) => {
currentIndex.value = index;
};
const onSwiperChange = (e: any) => {
currentIndex.value = e.detail.current;
};
return {
tabs,
currentIndex,
changeTab,
onSwiperChange,
};
},
};
</script>
<style>
.tab-container {
width: 100%;
}
.tab-scroll {
white-space: nowrap;
overflow-x: auto;
}
.tab-list {
display: flex;
}
.tab-item {
padding: 10px 20px;
cursor: pointer;
position: relative;
}
.tab-item.active {
color: #f10606;
}
.swiper-content {
height: 300px; /* 设置内容区域的高度 */
}
.swiper-item-content {
width: 100%;
height: 100%;
box-sizing: border-box;
padding: 20px;
}
.active::after {
content: '';
position: absolute;
/* background-image: url(../../static/checkDetails/action.png); */
background-size: 100%;
background: #f00;
background-repeat: no-repeat;
width: 40px;
height: 4px;
top: 38px;
left: 30px;
}
</style>

基本思路
1横向滚动的动画效果主要依靠scrollview自带的croll-with-animation="true"来设置
2 而底部下划线则是给当前激活的tab设置伪元素来实现
2:通过v-model实现索引值的绑定
以上我们只实现了基础的tab标签页效果,如果要实现常见的v-model如何实现?
<template>
<view class="tab-container">
<!-- Tab 标签滚动容器 -->
<scroll-view scroll-x="true" :scroll-left="scrollLeft" class="tab-scroll" scroll-with-animation="true">
<view class="tab-list">
<view
:id="'tab' + index"
v-for="(item, index) in list"
:key="index"
class="tab-item"
:class="{ active: index == activeIndex }"
@click="handleTabClick(item, index)"
>
<text class="tab_name"> {{ item.sku }}</text>
<text class="tab_num">{{ item.actualWeight }} / {{ item.outboundWeight }} </text>
</view>
</view>
</scroll-view>
</view>
</template>
<script setup lang="ts">
import { onLoad, onShow, onReady } from '@dcloudio/uni-app'
import { getCurrentInstance, computed } from 'vue'
// const currentTabId = ref('')
const tabWidth = ref(0)
const emits = defineEmits(['change', 'update:modelValue'])
const props = defineProps({
list: {
type: Array,
default: () => []
},
modelValue: {
type: Number,
default: 0
}
})
let activeIndex = ref(props.modelValue)
watch(
() => props.modelValue,
(newVal) => {
console.log('内部newVal', newVal)
console.log('内部newVal--type', typeof newVal)
activeIndex.value = newVal
}
)
const handleTabClick = (data, index) => {
activeIndex.value = index
let curData = props.list[index]
// currentTabId.value = data.skuId + index
emits('update:modelValue', activeIndex.value)
emits('change', { data: curData, index: activeIndex.value })
}
</script>
<style scoped lang="scss">
.tab-scroll {
white-space: nowrap;
overflow-x: auto;
}
.tab-item {
padding: 20rpx 40rpx; /* 使用px */
display: inline-block;
position: relative;
font-size: 26rpx;
color: #343b52;
cursor: pointer;
vertical-align: top;
}
.tab_num {
color: #76c802;
display: inline-block;
}
.active {
color: #694feb;
}
.active::after {
content: '';
position: absolute;
/* background-image: url(../../static/checkDetails/action.png); */
background-size: 100%;
background: #694feb;
background-repeat: no-repeat;
width: 100rpx;
height: 4rpx;
top: 64rpx;
left: 40rpx;
}
</style>
父组件中
<Tabs
:list="detailData.skuList"
v-model="currentIndex"
@change="changeTab"
v-if="detailData.skuList && detailData.skuList.length > 0"
/>
const currentIndex=ref(0)
const changeTab = (data) => {
console.log('changetab回调', data)
currentSkuData.value = data.data
tableParams.value.materialId = data.data.skuId
// console.log('currentSkuData--', currentSkuData.value)
// currentIndex.value = data.index
if (data.data.hasCode == 1) {
getTableList()
}
}
3实现内容区滚动tab标签页滚动定位
核心:获取tab的宽度。每次滚动内容区的时候通过计算 const tabLeft = tabWidth.value * activeIndex.value,然后给scroview的 :scroll-left="scrollLeft"设置scrollLeft值既可
<template>
<view class="tab-container">
<!-- Tab 标签滚动容器 -->
<scroll-view scroll-x="true" :scroll-left="scrollLeft" class="tab-scroll" scroll-with-animation="true">
<view
:id="'tab' + index"
v-for="(item, index) in list"
:key="index"
class="tab-item"
:class="{ active: index == activeIndex }"
@click="handleTabClick(item, index)"
>
<text class="tab_name"> {{ item.sku }}</text>
<text class="tab_num">{{ item.actualWeight }} / {{ item.outboundWeight }} </text>
</view>
</view>
</scroll-view>
</view>
</template>
<script setup lang="ts">
import { onLoad, onShow, onReady } from '@dcloudio/uni-app'
import { getCurrentInstance, computed } from 'vue'
// const currentTabId = ref('')
const tabWidth = ref(0)
const emits = defineEmits(['change', 'update:modelValue'])
const props = defineProps({
list: {
type: Array,
default: () => []
},
modelValue: {
type: Number,
default: 0
}
onMounted(async () => {
let res = await getEle()
tabWidth.value = res[1].width
console.log('getEle--res-', res)
console.log('getEle--res-wid', res[0].width)
})
const getEle = () => {
const { proxy } = getCurrentInstance()
return new Promise((resolve, reject) => {
let view = uni.createSelectorQuery().in(proxy)
view
.selectAll('.tab-item')
.boundingClientRect((data) => {
resolve(data)
})
.exec()
})
}
const scrollLeft = computed(() => {
const tabLeft = tabWidth.value * activeIndex.value
return tabLeft
})
let activeIndex = ref(props.modelValue)
watch(
() => props.modelValue,
(newVal) => {
console.log('内部newVal', newVal)
console.log('内部newVal--type', typeof newVal)
activeIndex.value = newVal
}
)
const handleTabClick = (data, index) => {
activeIndex.value = index
let curData = props.list[index]
// currentTabId.value = data.skuId + index
emits('update:modelValue', activeIndex.value)
emits('change', { data: curData, index: activeIndex.value })
}
</script>
<style scoped lang="scss">
.tab-scroll {
white-space: nowrap;
overflow-x: auto;
}
.tab-item {
padding: 20rpx 40rpx; /* 使用px */
display: inline-block;
position: relative;
font-size: 26rpx;
color: #343b52;
cursor: pointer;
vertical-align: top;
}
.tab_num {
color: #76c802;
display: inline-block;
}
.active {
color: #694feb;
}
.active::after {
content: '';
position: absolute;
/* background-image: url(../../static/checkDetails/action.png); */
background-size: 100%;
background: #694feb;
background-repeat: no-repeat;
width: 100rpx;
height: 4rpx;
top: 64rpx;
left: 40rpx;
}
</style>
更多推荐



所有评论(0)