滚动列表组件,自定义滚动列表

275 阅读2分钟

scrollList组件 - vue3

子组件

<template>
	<view>
		<scroll-view scroll-x="true" @scroll="scrollChange" id='scrollBox'>
			<view id='scrollContain' class="contain" :style="scrollContain">
				<view class="item" :style="itemStyle" v-for="item in datas.titleList" @click="clickItem(item.name)">
					<view class="icon">
						<image class="image" :src="item.iconPath" mode="aspectFill"></image>
					</view>
					<view class="title" :style="{'fontSize':size}">
						{{item.name}}
					</view>
				</view>
			</view>
		</scroll-view>
		<view v-if="showScrollBar" class="scrollBar" :style="scrollBarStyle">
			<view :style="scrollSliderStyle" class="innerBar"></view>
		</view>
	</view>
</template>

<script setup>
	import {
		onMounted,
		reactive,
		ref
	} from 'vue';
	let datas = defineProps(['titleList', 'scrollBarWrapStyle', 'scrollContainStyle', 'scrollBarStyle', 'count','size','row' ])

	// 显示区域宽
	let scrollBoxWidth = ref(0)
	// 滚动容器部分 - 包含隐藏部分
	let scrollContain = ref({})
	let left = ref(0)
	// 滚动条容器
	let scrollBarStyle = ref({
		backgroundColor: '#f0f'
	})
	// 滚动条
	let scrollSliderStyle = ref({
		backgroundColor: '#00f',
		marginLeft: '0'
	})
	// 每一个item块
	let itemStyle = ref({
		width: '0px'
	})
	// 是否显示滚动条
	let showScrollBar = ref(true)
	onMounted(() => {
		initScroll()
		initStyle()
	});
	// 初始化滚动列表 - 宽,高,显示/隐藏部分
	const initScroll = () => {
		// console.log(datas.titleList.length);
		const query = uni.createSelectorQuery().in();
		query.select('#scrollBox').boundingClientRect(res => {
			scrollBoxWidth.value = res.width; // 显示区域宽
			let {row} = datas
			itemStyle.value = {
				...itemStyle.value,
				width: res.width / datas.count + 'px'
			}
			console.log(itemStyle.value);
			if(!row || row == 1){
				// 单行
				scrollContain.value = { //容器总宽
					...scrollContain.value,
					width: parseFloat(itemStyle.value.width) * datas.titleList.length + 'px'
				}
			}else{
                          // 多行
				let itemList = datas.titleList.length
				if(datas.titleList.length%2!=0){itemList = datas.titleList.length + 1}
				let col = Math.ceil(itemList / row)
				scrollContain.value = {
					...scrollContain.value,
					width: parseFloat(itemStyle.value.width) * col + 'px'
				}
			}
			console.log(scrollContain.value);
			// 当总宽度等于显示宽度时隐藏滚动条
			if (parseFloat(scrollContain.value.width) <= res.width) {
				showScrollBar.value = false
			}
		}).exec();
	}
	// 初始化滚动条
	const initStyle = () => {
		if (datas.scrollBarWrapStyle) {
			changeScrollBarWrapStyle();
		}
		if (datas.scrollBarStyle) {
			changeScrollBarStyle();
		}
		if (datas.scrollContainStyle) {
			changeScrollContain();
		}
	}
	// 修改内部容器样式
	const changeScrollContain = () => {
		scrollContain.value = {
			...scrollContain.value,
			backgroundColor: datas.scrollContainStyle.backgroundColor
		};
	}
	// 修改滚动条容器样式
	const changeScrollBarWrapStyle = () => {
		// console.log(datas.scrollBarWrapStyle.backgroundColor);
		scrollBarStyle.value = datas.scrollBarWrapStyle;
	};
	// 修改滚动条样式
	const changeScrollBarStyle = () => {
		scrollSliderStyle.value = {
			...scrollSliderStyle.value,
			backgroundColor: datas.scrollBarStyle.backgroundColor
		};
	};
	// 设置滚动距离
	const scrollChange = (e) => {
		let value = parseFloat(scrollContain.value.width) - scrollBoxWidth.value;
		let newValue = e.detail.scrollLeft / value;
		scrollSliderStyle.value = {
			...scrollSliderStyle.value,
			marginLeft: newValue * 60 + 'rpx'
		};
	};
	const clickItem = (name) => {
		console.log(name);
	};
</script>

<style scoped>
	.scrollBar {
		position: relative;
		top: -20rpx;
		width: 100rpx;
		height: 10rpx;
		margin: auto;
		border-radius: 20px;

	}

	.innerBar {
		width: 40rpx;
		height: 10rpx;
		border-radius: 20px;
	}

	.contain {
		display: flex;
		flex-wrap: wrap;
	}

	.item {
		box-sizing: border-box;
		padding: 10rpx;
		height: 200rpx;
		text-align: center;
		display: flex;
		flex-direction: column;
		justify-content: center;
		align-items: center;
	}


	.image {
		width: 100rpx;
		height: 100rpx;
		border-radius: 20rpx;
	}
</style>

父组件

<script setup>
	import {
		onMounted,
		reactive,
		ref
	} from 'vue';
	import scrollList from '../../components/scrollList/scrollList.vue'
	// 数据源
	const lists = ref([{
			iconPath: '../../static/logo.png',
			name: '张三'
		},
		{
			iconPath: '../../static/logo.png',
			name: '李四'
		},
		{
			iconPath: '../../static/logo.png',
			name: '李四'
		},
		{
			iconPath: '../../static/logo.png',
			name: '王五'
		},
		{
			iconPath: '../../static/logo.png',
			name: '赵六'
		},
		{
			iconPath: '../../static/logo.png',
			name: '赵六'
		},
		{
			iconPath: '../../static/logo.png',
			name: '赵六'
		},
		{
			iconPath: '../../static/logo.png',
			name: '赵六'
		},
	])
	// 下方滚动容器样式
	const scrollBarWrapStyle = ref({
		backgroundColor: '#f00'
	})
	// 下方滚动条样式
	const scrollBarStyle = ref({
		backgroundColor: '#000'
	})
	// 内容区域样式
	const scrollContainStyle = ref({
		backgroundColor: '#fff'
	})
	// 文字大小 - 支持px/rpx/em
	const size = ref('20rpx')
	// 显示数量
	const count = ref(3)
	// 行数
	let row = ref(2);
	onMounted(() => {

	});
	
</script>
<template>
	<view>
		<scrollList :titleList="lists" :scrollBarWrapStyle="scrollBarWrapStyle" :scrollBarStyle="scrollBarStyle"
			:count="count" :scrollContainStyle="scrollContainStyle" :size="size" :row="row">
		</scrollList>
	</view>
</template>



<style scoped>
	.grid-text {
		font-size: 14px;
		color: #909399;
	}
</style>

124d76e9c7b3c6352effe70da288920d.gif