uni_app组件实现tab选项卡滑动切换,支持默认选中,vue3+ts+setup

效果截图:

前言:

最近开发小程序,需要用到tabs组件,在标签多的时候,可以左右滑动。在插件库找到uView UI,但是这个库插件体积不算太小,小程序尽可能需要减少包体积,于是就打算自己封装一下。

主要能力:选中的tab会自动移动到组件的中间位置,支持默认选中第几个tab,可联动获取数据,支持和swiper联动使用。

主要方法:scroll-view

scroll-x:true //允许横向滚动

scroll-left //设置横向滚动条位置

scroll-with-animation  //在设置滚动条位置时使用动画过渡

tabs接受的参数props,tablist是父组件传递过来的tab数组,defaultsSelectIndex默认选中的第几个tab。

<tabs :tablist='list' :defaultSelectIndex='defaultSelectIndex' @select='change'></tabs>

计算每个tab的宽度

onMounted(() => {
		const query = uni.createSelectorQuery().in(getCurrentInstance());
		 
		query.selectAll('.tabs-scroll_item').boundingClientRect((data:Array<UniApp.NodeInfo>) => {
			let dataLen = data.length;
			for (let i = 0; i < dataLen; i++) {
				//  scroll-view 子元素组件距离左边栏的距离
				itemList.value[i].left = data[i].left;
				//  scroll-view 子元素组件宽度
				itemList.value[i].width = data[i].width
			}
		}).exec()


	})

select选中的tab暴露给父组件的方法。

const emits=defineEmits<{
		(e : 'select',value : ItabItem) : void
	}>()

隐藏滑动条

/* 隐藏滚动条*/
	::v-deep.uni-scroll-view::-webkit-scrollbar {
		display: none
	}

组件实现代码tabs.vue

<template>
	<view class="nav">
		<scroll-view class="tabs" scroll-x="true" scroll-with-animation :scroll-left="scrollLeft">
			<view class="tabs-scroll">
				<view class="tabs-scroll_item" v-for=" (item,index) in itemList" :key="index"
					:class="{'active':selectIndex==index}" @click="chenked(index)">
					{
   
   {item.title}}
				</view>
			</view>
		</scroll-view>
	</view>
</template>

<script setup lang="ts">
	import { getCurrentInstance, onMounted, ref, watch } from "vue";
	const scrollLeft = ref<number>(0)
	const selectIndex = ref<number>(0)
 	const itemList = ref<Array<ItabItem>>()
	interface ItabItem {
		title : string
		width ?: number
		left ?: number
		id : number
	}
	interface Iprops {
		tablist : Array<ItabItem>
		defaultSelectIndex ?: number
	}
    
	const props = withDefaults(defineProps<Iprops>(), {
		tablist: () => [],
		defaultSelectIndex: 6
	})
	const emits=defineEmits<{
		(e : 'select',value : ItabItem) : void
	}>()
	const chenked = (index:number) => {
		selectIndex.value = index
		scrollLeft.value = 0
		for (let i = 0; i < index - 2; i++) {
			scrollLeft.value = scrollLeft.value + itemList.value[i]?.width
		}
		emits('select',props.tablist[index])
	}
	onMounted(() => {
		const query = uni.createSelectorQuery().in(getCurrentInstance());
		 
		query.selectAll('.tabs-scroll_item').boundingClientRect((data:Array<UniApp.NodeInfo>) => {
			let dataLen = data.length;
			for (let i = 0; i < dataLen; i++) {
				//  scroll-view 子元素组件距离左边栏的距离
				itemList.value[i].left = data[i].left;
				//  scroll-view 子元素组件宽度
				itemList.value[i].width = data[i].width
			}
		}).exec()


	})
	watch(() => [props.tablist, props.defaultSelectIndex], () => {
		itemList.value = props.tablist
		selectIndex.value = props.defaultSelectIndex
		if(props.defaultSelectIndex!==0){
			setTimeout(()=>{
				chenked(props.defaultSelectIndex)
			},50)
		}
	}, {
		immediate: true
	})
</script>
<style lang="scss" scoped>
	.nav {

		background-color: rgba(0, 0, 0, .1);
		position: fixed;
		z-index: 99;
		width: 100%;
		align-items: center;
		height: 100rpx;

		.tabs {
			flex: 1;
			overflow: hidden;
			box-sizing: border-box;
			padding-left: 30rpx;
			padding-right: 30rpx;

			.tabs-scroll {
				display: flex;
				align-items: center;
				flex-wrap: nowrap;
				box-sizing: border-box;

				.tabs-scroll_item {
					line-height: 60rpx;
					margin-right: 35rpx;
					flex-shrink: 0;
					padding-bottom: 10px;
					display: flex;
					justify-content: center;
					font-size: 16px;
					padding-top: 10px;
				}
			}
		}
	}


	.active {
		position: relative;
		color: #333;
		font-weight: 800;
	}

	.active::after {
		content: "";
		position: absolute;
		width: 40rpx;
		height: 8rpx;
		border-radius: 8rpx;
		background-color: #333;
		left: 0px;
		right: 0px;
		bottom: 0px;
		margin: auto;
	}

	/* 隐藏滚动条,但依旧具备可以滚动的功能 */
	::v-deep.uni-scroll-view::-webkit-scrollbar {
		display: none
	}
</style>

使用方法index.vue

<template>
	<view>
		<text style="text-align: center;width: 100%;display: block;"> 标题</text>
		<tabs :tablist='list' :defaultSelectIndex='defaultSelectIndex' @select='change'></tabs>
	</view>
	<button @click="add" style="margin-top: 100rpx;">父组件调用切换</button>
	
</template>

<script lang="ts" setup>
	import { ref } from "vue";
	const defaultSelectIndex=ref(0)
	const list = ref([
		
		{
			id: 1,
			title: '直播直播',
		},
		{
			id: 2,
			title: '热门推荐',
		},
		{
			id: 3,
			title: '音乐',
		},
		{
			id: 4,
			title: '经典小说',
		},
		{
			id: 5,
			title: '看书',
		},
		{
			id: 6,
			title: '短剧',
		},
		{
			id: 7,
			title: '相声评述',
		},
		{
			id: 8,
			title: '找书广场',
		},
	])
    const change=(value)=>{
		uni.showToast({
			title: value.title,
			duration: 2000
		});

	}
	const add=( )=>{
		defaultSelectIndex.value++
	}
</script>

<style>

</style>

希望本篇文章对你有所帮助,我也是根据自己的需求封装的,你也可以根据自己的需求在该代码上进行优化。

猜你喜欢

转载自blog.csdn.net/u012941592/article/details/133153866
今日推荐