vue3使用el-scrollbar(ElementPlus)制作自动滚屏功能

        前端在写一些页面时,比如可视化大屏,需要完成自动滚屏的功能,当然你可以去找现成的node依赖包搞定,但作为技术,我们需要了解且自己能完成这样的功能代码,因为部分公司严格管理package文件,不是你想引就能引。

        网上也有很多此类的代码,但99%的帖子会有下面这样的跳动问题,在视觉上不够丝滑,让人不爽。

滚屏抖动

        他们实现逻辑大概为下图样子,一个列表滚到顶部就切回顶部,这样就出现了跳动。

        那么该如何解决呢,网上剩余的1%帖子,给出了方案,如下图,复制一次原列表,在复制列表顶部到达可视区域的顶部时切回原列表的顶部,这样就达成了丝滑的无限的滚动功能。

       

滚屏丝滑

         滚动视图组件template内容。

<template>
	<el-scrollbar ref="scrollbarRef" 
		:height="height" 
		@scroll="onScroll"
		@mouseenter="onMouseEnter" 
		@mouseleave="onMouseLeave">
		<slot></slot>
	</el-scrollbar>
</template>

        slot插槽动态渲染列表,但什么情况下复制渲染列表呢,你们肯定知道在scrollHeight滚动高度超过clientHeight可视区域,就需要复制列表,否则不用复制,因为人家就没超过,不用滚动。

        但动态渲染,会让你无法在nextTick内获取到高度,这该怎么办呢?上面代码里的scroll事件,想必大家都看到了,当触发滚动事件时触发scroll事件,这样就能知道列表是否超出可视区域需要滚动了。

        直接放出完整代码,代码里有两种滚动方法requestAnimationFramesetScrollTop,选择你高兴的留下。

<template>
	<el-scrollbar ref="scrollbarRef" 
		:height="height" 
		@scroll="onScroll"
		@mouseenter="onMouseEnter" 
		@mouseleave="onMouseLeave">
		<slot></slot>
		<slot v-if="isDouble"></slot>
	</el-scrollbar>
</template>

<script setup lang="ts">

const props = defineProps({
	loop: {
		type: Boolean,
		default: false
	},
	speed: {
		type: Number,
		default: 50
	},
	height: {
		type: [String, Number],
		default: 'auto'
	},
});
const scrollbarRef = ref(null);
// 定时器
let interval = undefined;
// 滚动条组件内部节点
let wrap: any;
// 设置滚动条每次滚动距离
const scrollbarDistance = ref(0);

onMounted(() => {
	if (scrollbarRef.value && props.loop) {
		wrap = scrollbarRef.value!.wrapRef;
		autoScroll();
		// scroll();
	}
	nextTick(() => {
		
	});
});

onBeforeUnmount(() => {
	clear();
});

// 丝滑滚动代码
const isDouble =ref(false);
const onScroll = () => {
	isDouble.value = true;
};

// requestAnimationFrame动画
const flag = ref(true)
const scroll = () => {
	if (flag.value) {
		wrap.scrollTop += 1; // 设置滚动速度
		if (wrap.clientHeight + wrap.scrollTop >= wrap.scrollHeight) {
			wrap.scrollTop = 0; // 滚动到底部后跳回顶部
		}
	}
	setTimeout(() => {
		requestAnimationFrame(scroll); // 设置延迟,让滚动更缓慢
	}, props.speed);
};

// scroll滾動事件
const autoScroll = () => {
	if (interval) return;
	interval = setInterval(() => {
		if (scrollbarRef.value) {
			// 当滚动条滚动到底部时自动返回到顶部
			let f = isDouble.value ? (wrap!.scrollTop >= wrap!.scrollHeight / 2) : (wrap!.scrollTop + wrap!.clientHeight >= wrap!.scrollHeight);
			// if (wrap!.scrollTop + wrap!.clientHeight >= wrap!.scrollHeight) {
			// if (wrap!.scrollTop >= wrap!.scrollHeight / 2) {
			if (f) {
				scrollbarDistance.value = 0;
			} else {
				scrollbarDistance.value ++;
			}
			// 重置滚动条到顶部的距离
			scrollbarRef.value.setScrollTop(scrollbarDistance.value);
		}
	}, props.speed)
};
//鼠标进入滚动区域时要清除计时器,停止自动滚动
const onMouseEnter = () => {
	clear();
	flag.value = false;
};
//鼠标离开滚动区域时从当前位置开始自动滚动
const onMouseLeave = () => {
	scrollbarDistance.value = wrap!.scrollTop;
	autoScroll();
	flag.value = true;
};
// 清楚定时
const clear = () => {
	clearInterval(interval);
	interval = 0;
};
</script>

<style lang="scss" scoped></style>

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值