如何实现TikTok风格的垂直视频分屏滚动效果

来源:站长平台作者:台湾程序员头衔:程序员
导读:本期聚焦于小伙伴创作的《如何实现TikTok风格的垂直视频分屏滚动效果》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《如何实现TikTok风格的垂直视频分屏滚动效果》有用,将其分享出去将是对创作者最好的鼓励。

实现TikTok风格的垂直视频分屏滚动效果,核心是保证用户每次滑动后屏幕恰好完整展示一个视频,并且滑动结束后自动吸附到对应视频的位置,同时支持触摸滑动和鼠标滚轮两种操作方式。这种效果可以提升用户的观看体验,避免视频被截断或者滑动位置不准确的问题。

如何实现TikTok风格的垂直视频分屏滚动效果

核心实现原理

整个效果的实现可以分为三个核心部分:首先是布局层面,每个视频容器占满整个可视区域,多个视频容器垂直排列;其次是交互层面,监听用户的触摸滑动和鼠标滚轮事件,计算滑动的距离和方向;最后是吸附逻辑,当滑动结束后,根据当前滑动的位置判断应该展示哪个视频,然后通过动画将对应视频滚动到可视区域顶部。

布局结构设计

首先我们需要构建基础的HTML结构,每个视频项占满整个屏幕,容器设置固定高度,内部视频元素自适应容器大小:

<div class="video-scroll-container">
  <div class="video-item">
    <video src="video1.mp4" loop muted autoplay></video>
  </div>
  <div class="video-item">
    <video src="video2.mp4" loop muted autoplay></video>
  </div>
  <div class="video-item">
    <video src="video3.mp4" loop muted autoplay></video>
  </div>
</div>

对应的CSS样式需要保证每个视频项占满屏幕,容器支持垂直滚动并隐藏滚动条:

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}
html, body {
  height: 100%;
  overflow: hidden;
}
.video-scroll-container {
  height: 100vh;
  overflow-y: scroll;
  scroll-snap-type: y mandatory;
  /* 隐藏滚动条 */
  scrollbar-width: none;
}
.video-scroll-container::-webkit-scrollbar {
  display: none;
}
.video-item {
  height: 100vh;
  scroll-snap-align: start;
  position: relative;
}
.video-item video {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

交互逻辑实现

虽然CSS的scroll-snap-type属性已经可以实现基础的吸附效果,但是为了兼容更多场景以及自定义滑动逻辑,我们可以通过JavaScript监听触摸和滚轮事件来完善交互:

// 获取滚动容器
const scrollContainer = document.querySelector('.video-scroll-container');
// 记录触摸起始位置
let touchStartY = 0;
// 记录是否正在执行吸附动画,避免重复触发
let isAnimating = false;
// 单个视频项的高度,即屏幕高度
const itemHeight = window.innerHeight;

// 监听触摸开始事件
scrollContainer.addEventListener('touchstart', (e) => {
  if (isAnimating) return;
  touchStartY = e.touches[0].clientY;
});

// 监听触摸结束事件
scrollContainer.addEventListener('touchend', (e) => {
  if (isAnimating) return;
  const touchEndY = e.changedTouches[0].clientY;
  // 计算滑动距离,正数表示向下滑,负数表示向上滑
  const deltaY = touchEndY - touchStartY;
  // 滑动阈值,超过50px才触发切换
  const threshold = 50;
  // 当前已经滚动的距离
  const currentScrollTop = scrollContainer.scrollTop;
  // 计算当前所在的视频索引
  let currentIndex = Math.round(currentScrollTop / itemHeight);
  // 根据滑动距离调整目标索引
  if (deltaY < -threshold) {
    // 向上滑,切换到下一个视频
    currentIndex = Math.min(currentIndex + 1, scrollContainer.children.length - 1);
  } else if (deltaY > threshold) {
    // 向下滑,切换到上一个视频
    currentIndex = Math.max(currentIndex - 1, 0);
  }
  // 执行吸附动画
  scrollToIndex(currentIndex);
});

// 监听鼠标滚轮事件
scrollContainer.addEventListener('wheel', (e) => {
  if (isAnimating) return;
  e.preventDefault();
  // 滚轮向下滚,切换到下一个视频
  let currentIndex = Math.round(scrollContainer.scrollTop / itemHeight);
  if (e.deltaY > 0) {
    currentIndex = Math.min(currentIndex + 1, scrollContainer.children.length - 1);
  } else {
    // 滚轮向上滚,切换到上一个视频
    currentIndex = Math.max(currentIndex - 1, 0);
  }
  scrollToIndex(currentIndex);
}, { passive: false });

// 滚动到指定索引的视频项
function scrollToIndex(index) {
  isAnimating = true;
  const targetScrollTop = index * itemHeight;
  // 使用requestAnimationFrame实现平滑动画
  const startScrollTop = scrollContainer.scrollTop;
  const distance = targetScrollTop - startScrollTop;
  const duration = 300; // 动画时长300ms
  let startTime = null;

  function animate(currentTime) {
    if (!startTime) startTime = currentTime;
    const elapsedTime = currentTime - startTime;
    const progress = Math.min(elapsedTime / duration, 1);
    // 使用缓动函数让动画更自然
    const easeProgress = easeOutCubic(progress);
    scrollContainer.scrollTop = startScrollTop + distance * easeProgress;
    if (progress < 1) {
      requestAnimationFrame(animate);
    } else {
      isAnimating = false;
    }
  }

  // 缓动函数:三次方缓出
  function easeOutCubic(t) {
    return 1 - Math.pow(1 - t, 3);
  }

  requestAnimationFrame(animate);
}

兼容与优化说明

上述代码已经同时兼容了移动端触摸滑动和PC端鼠标滚轮操作,并且通过isAnimating标志位避免了动画执行期间的重复触发问题。如果需要适配更多场景,还可以添加以下优化:

  • 监听窗口 resize 事件,当屏幕高度变化时重新计算itemHeight的值,更新每个视频项的高度
  • 给视频添加播放控制逻辑,切换到当前视频时自动播放,离开时暂停,减少性能消耗
  • 如果视频数量较多,可以结合虚拟列表的思路,只渲染可视区域附近的视频项,提升渲染性能

常见问题排查

在实际开发中可能会遇到以下问题:

  • 吸附位置不准确:检查每个视频项的高度是否和itemHeight一致,是否存在 padding 或者 margin 影响高度计算
  • 滑动触发不灵敏:可以调整滑动阈值threshold的大小,根据产品需求设置合适的触发范围
  • 动画卡顿:可以减少动画时长,或者优化缓动函数的计算逻辑,避免复杂的运算

vertical_video_scrollauto_snapfull_screen_videoscroll_adsorption修改时间:2026-06-17 12:45:19

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。