SeamlessScroll 组件介绍
功能说明
SeamlessScroll
是一个实现无缝滚动效果的 Vue 3 组件,主要功能包括:
- 无缝垂直滚动:支持向上或向下无缝滚动内容
- 可控制滚动速度 :通过
speed
属性调整滚动速度 - 可控制滚动方向 :通过
direction
属性设置向上('up')或向下('down')滚动 - 鼠标悬停暂停:鼠标悬停时自动暂停滚动,移开后继续
- 动态内容同步:自动同步两个滚动容器的内容,确保无缝衔接
- 重置功能 :提供 reset 方法可重置滚动位置
组件源码
js
<script setup>
import { onBeforeUnmount, onMounted, ref } from 'vue'
const props = defineProps({
speed: {
type : Number,
default: 1000
},
direction: {
type : String,
default: 'up'
}
})
const box = ref(null)
const refRoll1 = ref(null)
const refRoll2 = ref(null)
let top = 0
let height = 0
let shadowHeight = 0
const sp = props.speed / 1000
let end = false
let isMouseHover = false
/**
* 刷新滚动内容的位置和高度
* 通过比较两个滚动元素的高度来同步内容
*/
function refresh () {
height = refRoll1.value.clientHeight
shadowHeight = refRoll2.value.clientHeight
if (shadowHeight !== height) {
refRoll2.value.innerHTML = refRoll1.value.innerHTML
}
if (top < 0) {
if (Math.abs(top) >= height) {
const tmp = refRoll1.value
refRoll1.value = refRoll2.value
refRoll2.value = tmp
top = 0
}
refRoll1.value.style.transform = `translate3d(0,${top}px,0)`
refRoll2.value.style.transform = `translate3d(0,${height + top}px,0)`
} else {
if (Math.abs(top) >= height) {
const tmp = refRoll1.value
refRoll1.value = refRoll2.value
refRoll2.value = tmp
top = -height
}
refRoll1.value.style.transform = `translate3d(0,${top}px,0)`
refRoll2.value.style.transform = `translate3d(0,${top - height}px,0)`
}
}
/**
* 执行动画帧函数,实现无缝滚动效果
* 使用requestAnimationFrame来优化动画性能
*/
function doAnimationFrame () {
requestAnimationFrame(() => {
if (end) {
return
}
// 鼠标悬停时暂停滚动
if (isMouseHover) {
refresh()
doAnimationFrame()
return
}
// 根据容器高度和方向控制滚动
if (height > box.value.clientHeight) {
if (props.direction === 'down') {
top += sp
}
if (props.direction === 'up') {
top -= sp
}
} else {
top = 0
}
refresh()
doAnimationFrame()
})
}
/**
* 鼠标进入容器时的处理函数
* 设置标志位以暂停滚动
*/
function onMouseEnter () {
isMouseHover = true
}
/**
* 鼠标离开容器时的处理函数
* 恢复滚动状态
*/
function onMouseLeaver () {
isMouseHover = false
}
// 组件挂载后开始执行动画
onMounted(doAnimationFrame)
// 组件销毁前设置结束标志,停止动画
onBeforeUnmount(() => {
end = true
})
/**
* 重置滚动位置到初始状态
*/
function reset () {
top = 0;
refresh();
}
// 暴露reset方法供外部调用
defineExpose({
reset
})
</script>
<template>
<div
ref="box"
class="hb-admin-roll-list-com"
@mouseenter="onMouseEnter"
@mouseleave="onMouseLeaver"
>
<!-- 滚动内容容器1 -->
<div
ref="refRoll1"
class="roll-item"
>
<div class="list-item">
<slot />
</div>
</div>
<!-- 滚动内容容器2(用于实现无缝滚动效果) -->
<div
ref="refRoll2"
class="roll-item"
/>
</div>
</template>
<style scoped>
.hb-admin-roll-list-com{
width: 100%;
height: 100%;
overflow: hidden;
position: relative;
}
.hb-admin-roll-list-com::-webkit-scrollbar{
display: none;
}
.roll-item{
width: 100%;
position: absolute;
}
.list-item{
}
</style>
使用方法
基本用法
vue
<template>
<SeamlessScroll :speed="800" direction="up">
<div>滚动内容1</div>
<div>滚动内容2</div>
<div>滚动内容3</div>
</SeamlessScroll>
</template>
<script setup>
import SeamlessScroll from './components/SeamlessScroll.vue'
</script>
属性说明
属性名 | 类型 | 默认值 | 说明 |
---|---|---|---|
speed | Number | 1000 | 滚动速度,数值越大滚动越慢 |
direction | String | 'up' | 滚动方向,可选 'up' 或 'down' |
方法说明
方法名 | 说明 |
---|---|
reset() | 重置滚动位置到初始状态 |
调用方法示例
vue
<template>
<SeamlessScroll ref="scrollRef" :speed="1200" direction="down">
<div v-for="item in list" :key="item.id">
{{ item.content }}
</div>
</SeamlessScroll>
<button @click="resetScroll">重置滚动</button>
</template>
<script setup>
import { ref } from 'vue'
import SeamlessScroll from './components/SeamlessScroll.vue'
const scrollRef = ref(null)
const resetScroll = () => {
scrollRef.value.reset()
}
</script>
工作原理
该组件通过以下方式实现无缝滚动效果:
- 创建两个相同的滚动容器(refRoll1 和 refRoll2)
- 使用
requestAnimationFrame
实现高性能动画 - 通过 CSS
transform: translate3d()
控制两个容器的位置 - 当一个容器完全移出视野时,将其移动到另一个容器的末尾
- 通过不断更新
top
值实现滚动效果 - 利用
clientHeight
计算容器高度,确保内容无缝衔接
注意事项
- 确保父容器有明确的高度设置
- 滚动内容需要有明确的高度
- 组件会自动隐藏滚动条
- 鼠标悬停可临时暂停滚动效果