vue3 无缝滚动

SeamlessScroll 组件介绍

功能说明

SeamlessScroll 是一个实现无缝滚动效果的 Vue 3 组件,主要功能包括:

  1. 无缝垂直滚动:支持向上或向下无缝滚动内容
  2. 可控制滚动速度 :通过 speed 属性调整滚动速度
  3. 可控制滚动方向 :通过 direction 属性设置向上('up')或向下('down')滚动
  4. 鼠标悬停暂停:鼠标悬停时自动暂停滚动,移开后继续
  5. 动态内容同步:自动同步两个滚动容器的内容,确保无缝衔接
  6. 重置功能 :提供 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>

工作原理

该组件通过以下方式实现无缝滚动效果:

  1. 创建两个相同的滚动容器(refRoll1refRoll2
  2. 使用 requestAnimationFrame 实现高性能动画
  3. 通过 CSS transform: translate3d() 控制两个容器的位置
  4. 当一个容器完全移出视野时,将其移动到另一个容器的末尾
  5. 通过不断更新 top 值实现滚动效果
  6. 利用 clientHeight 计算容器高度,确保内容无缝衔接

注意事项

  1. 确保父容器有明确的高度设置
  2. 滚动内容需要有明确的高度
  3. 组件会自动隐藏滚动条
  4. 鼠标悬停可临时暂停滚动效果
相关推荐
孜孜不倦不忘初心2 分钟前
mac安装nvm及问题记录
前端·node.js
Richar4 分钟前
Object.freeze()注意事项
前端·javascript
TA远方4 分钟前
【HTML】JavaScript Canvas 图像截取与保存完整指南
前端·javascript·html·canvas·截图·截取
Asize5 分钟前
JavaScript 数据类型解析:从 null 与 undefined 的迷思到栈堆内存真相
前端·javascript·面试
anyup9 分钟前
分享 5 套 uni-app 实用主题,一键适配暗黑模式
前端·uni-app·视觉设计
李白的天不白10 分钟前
vue3 ts 配置smartadmin相关配置
前端
起这个名字28 分钟前
Typescript 装饰器执行顺序
前端
LDX前端校草28 分钟前
position属性值及用法
前端·javascript·面试
Bigfish_coding33 分钟前
前端转agent-第一周【python】-05 Ollama+Qwen3实战:会话记忆实战
前端
x***r15135 分钟前
.NET 10 SDK 安装教程(dotnet-sdk-10.0.100-win-x64详细步骤)
java·服务器·前端