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. 鼠标悬停可临时暂停滚动效果
相关推荐
a1117763 分钟前
原生 Markdown 阅读与编辑器 开源项目
前端·开源·软件
laity173 分钟前
python发光表白爱心(从零到一实现)
前端·后端
程序员爱钓鱼12 分钟前
Rust impl详解:为Struct定义方法与关联函数
前端·后端·rust
用户0595401744622 分钟前
Qdrant 召回不一致踩坑实录:跑了 300 次测试才发现是索引没刷新
前端·css
Highcharts.js33 分钟前
Highcharts 主流前端框架无缝集成指南
前端·vue.js·前端框架·highcharts·可视化图表
JAVA面经实录91735 分钟前
网络编程基础(Java Web/分布式前置·完整版)(十一)
java·前端·网络
IT_陈寒37 分钟前
搞不定JavaScript的数组去重?你可能漏了这两个坑
前端·人工智能·后端
三8441 小时前
CSRF跨站请求伪造基础
前端·csrf
岁岁种桃花儿1 小时前
Vue核心语法第十一篇:绑定样式
前端·javascript·vue.js