requestAnimationFrame实现单张图片无缝持续滚动

  • A+
所属分类:Web前端
摘要

在很久以前,有写过一个使用 js 实现单张图片持续滚动图片的 代码,但那一版实现会持续操作DOM,向DOM中插入元素,性能较差,最近发现 requestAnimationFrame 通过 动画的方式实现图片滚动更加方便,遂重新实现了一版,效果更赞,性能更好。


背景

在很久以前,有写过一个使用 js 实现单张图片持续滚动图片的 代码,但那一版实现会持续操作DOM,向DOM中插入元素,性能较差,最近发现 requestAnimationFrame 通过 动画的方式实现图片滚动更加方便,遂重新实现了一版,效果更赞,性能更好。

效果如下

requestAnimationFrame实现单张图片无缝持续滚动

requestAnimationFrame实现单张图片无缝持续滚动

requestAnimationFrame实现单张图片无缝持续滚动

requestAnimationFrame实现单张图片无缝持续滚动

需求描述

需要单张图片在可视区域内无缝持续向上滚动或向左滚动,由于向下和向右属于反着坐标轴移动图片,和正常DOM元素插入展示顺序也相反,遂不考虑此种场景。

代码实现

<!DOCTYPE html> <html lang="en">     <head>         <meta charset="UTF-8" />         <title>滚动图片</title>         <style>             /*竖向滚动*/             #container {                 width: 300px;                 height: 150px;                 overflow: hidden;                 margin: 100px;             }             #wrap {                 width: 100%;                 height: auto;                 display: flex;                 flex-direction: column;                 align-items: center;                 transform: translatez(0);             }              img {                 width: 100%;                 height: auto;             }             /*横向滚动*/             /* #container {                 width: 300px;                 height: 150px;                 overflow: hidden;                 margin: 100px;             }             #wrap {                 width: auto;                 height: 100%;                 display: flex;                 flex-wrap: nowrap;                 align-items: center;                 transform: translatez(0);             }             img {                 width: auto;                 height: 100%;             } */         </style>     </head>     <body>         <div id="container">             <div id="wrap">                 <!-- 横图 -->                 <!-- <img                     src="https://img1.baidu.com/it/u=49865366,3040475020&fm=253&fmt=auto&app=138&f=JPEG?w=751&h=500"                     alt=""                 /> -->                 <!-- 竖图 -->                 <img                     src="https://img0.baidu.com/it/u=3724390669,1663648862&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=752"                     alt=""                 />             </div>         </div>         <script>             // 功能:实现图片无缝向上滚动             // run:运行图片轮播             // pause:暂停图片轮播             function imageScroll() {                 // 执行动画函数                 const requestAnimationFrame =                     window.requestAnimationFrame ||                     window.webkitRequestAnimationFrame ||                     window.mozRequestAnimationFrame;                 // 取消执行动画函数                 const cancelAnimationFrame =                     window.cancelAnimationFrame ||                     window.webkitCancelAnimationFrame ||                     window.mozCancelAnimationFrame;                 // 初始化定义轮播函数                 requestId = null;                 return function () {                     return {                         // imgWrap:图片容器,放置多张图片,整体进行滚动                         // imgView: 图片所展示区域的窗口view                         // step: 每次移动的距离                         // direction: 滚动方向,默认 "top" 持续向上滚动,可选值为 "top" 和 "left"                         run: (imgWrap, imgView, step = 1, direction = "top") => {                             if (!imgWrap || !imgView) {                                 console.warn("请传入参数形如[图片包裹容器,图片展示容器]");                                 return false;                             }                             // 获取窗口宽度                             const containerWidth = parseInt(imgView.clientWidth);                             // 获取窗口高度                             const containerHeight = parseInt(imgView.clientHeight);                             // 获取图片元素                             const imgElem = imgWrap.querySelector("img");                             // 获取图片宽度                             const imgWidth = parseInt(imgElem.width);                             // 获取图片高度                             const imgHeight = parseInt(imgElem.height);                             // 初始化移动距离                             let distance = 0;                             // 定义 transform 值名称                             let transformV;                             // 初始化图片移动置为0的边界长度                             let boundaryValue = 0;                             switch (direction) {                                 case "left":                                     // 向左滚动,值为 translateX                                     transformV = "translateX";                                     // 置为 0 的边界值为图片宽度                                     boundaryValue = parseFloat(imgWidth);                                     // 克隆的图片个数,至少克隆一张                                     const num1 = Math.ceil(containerWidth / imgWidth) || 1;                                     for (let index = 0; index < num1; index++) {                                         // 克隆一张图片并插入到图片最后面                                         imgWrap.appendChild(                                             imgWrap.querySelector("img").cloneNode(true)                                         );                                     }                                     break;                                 default:                                     // 向上滚动,值为 translateY                                     transformV = "translateY";                                     // 置为 0 的边界值为图片高度                                     boundaryValue = parseFloat(imgHeight);                                     // 克隆的图片个数,至少克隆一张                                     const num2 = Math.ceil(containerHeight / imgHeight) || 1;                                     for (let index = 0; index < num2; index++) {                                         // 克隆一张图片并插入到图片最后面                                         imgWrap.appendChild(                                             imgWrap.querySelector("img").cloneNode(true)                                         );                                     }                                     break;                             }                             // 定义滚动动画回调函数                             const scroll = () => {                                 // 移动的距离=已经移动的距离+每步的长度                                 distance = distance + step;                                 // 设置图片容器的 transform                                 imgWrap.style.transform = `${transformV}(-${distance}px)`;                                 // 关键行:当移动距离大于边界值时,重置 distance=0                                 if (distance >= boundaryValue) {                                     distance = 0;                                 }                                 // console.log("11", requestId);                                 // 再次调用滚动动画                                 requestId = requestAnimationFrame(scroll);                             };                             // 执行滚动动画,传入滚动动画回调函数                             requestId = requestAnimationFrame(scroll);                             // console.log("00", requestId);                         },                         // 暂停动画                         pause: () => {                             cancelAnimationFrame(requestId);                         },                     };                 };             }              window.onload = () => {                 const scroll = imageScroll();                 // 向左滚动                 // scroll().run(                 //     document.getElementById("wrap"),                 //     document.getElementById("container"),                 //     0.5,                 //     "left"                 // );                 // 向上滚动                 scroll().run(                     document.getElementById("wrap"),                     document.getElementById("container"),                     1,                     "top"                 );                 // 通过定时器可以实现图片滚动几秒后暂停,如下表示先滚动 4s 后暂停,之后每个隔 2s 再滚动,2秒后再暂停                 setInterval(() => {                     scroll().pause();                     setTimeout(() => {                         scroll().run(                             document.getElementById("wrap"),                             document.getElementById("container"),                             1,                             "top"                         );                     }, 2000);                 }, 4000);             };         </script>     </body> </html>

备注

对于向上滚动和向左滚动两种效果,css 样式要同步修改,支持横图、竖图滚动。

代码中用到了百度图片,侵删。

参考链接

如何设计实现无缝轮播  【同时这里其他朋友答案也都很赞,收藏了】

requestAnimationFrame 知多少?【相关知识点与优势可参考这里】