原生JS使用transform实现banner的无限滚动效果

2020-07-15 23:43:01 来源:易采站长站 作者:

功能

5289b216dc4904aaaec181e12c2cc13.png

默认情况无限循环向右移动点击数字切换到对应图片点击左右切换可切换图片

原理

首先说下原理。

在布局上所有的图片都是重叠的,即只要保证Y方向对齐即可,当前可见的图z-index层级最高。每隔3s中更换一张图片,使用setTimeout定时。使用gIndex记录当前可视区域的展示的是哪张图片下标,每次更换,计算下一张图片的下标。通过requestAnimationFrame实现一次图片切换的动画。

这种方法也可以做到整个页面始终只有2个img标签,而不必把所有的img节点全部创建出来,要点是每次更换不可见img的src。
87e184bcaecddcfef463e562f78736a.png

动画的实现

首先定义一个timestap,这个值记录每个帧移动多少距离。定义初始step=0,记录移动的步数。每次移动的距离moveWidth是timestamp*step,图片1向右移动增加moveWidth,图片2从左侧进入moveWidth。因此,图片1的transform是translate(moveWidth), 而图片2的transform则是translate(moveWidth-图片宽度)。step+1如果moveWidth>图片宽度,步骤5,否则requestAnimationFrame请求下一次执行,继续2-4.图片1和2都将位置放置在起始位置,图片2的z-index设置为最高。

这样就完成了一次移动的动画。

html代码

<header>    <p class="box">        <img src="imgs/banner1.jpg">        <img src="imgs/banner2.jpg">        <img src="imgs/banner3.jpg">        <img src="imgs/banner4.jpg">    </p>    <p class="buttons">        <p class="active">1</p>        <p>2</p>        <p>3</p>        <p>4</p>    </p>    <p class="left">        <p class="arrow"></p>    </p>    <p class="right">        <p class="arrow"></p>    </p></header>

JS代码

var timeout = null;window.onload = function () {    var oLeft = document.querySelector('.left');    var oRight = document.querySelector('.right');    var oButton = document.querySelector('.buttons');    var oButtons = document.querySelectorAll('.buttons p');    var oImgs = document.querySelectorAll('.box img');    var imgWidth = oImgs[0].width;    var gIndex = 0;    begainAnimate();    // 绑定左右点击事件    oLeft.onclick = function () {        clearTimeout(timeout);        leftMove();        begainAnimate();    };    oRight.onclick = function () {        clearTimeout(timeout);        rightMove();        begainAnimate();    };    // 绑定数字序号事件    oButton.onclick = function (event) {        clearTimeout(timeout);        var targetEl = event.target;        var nextIndex = (+targetEl.innerText) - 1;        console.log(nextIndex);        rightMove(nextIndex);        begainAnimate();    }    // 默认初始动画朝右边    function begainAnimate() {        clearTimeout(timeout);        timeout = setTimeout(function () {            rightMove();            begainAnimate();        }, 3000);    }    // 向左移动动画    function leftMove() {        var nextIndex = (gIndex - 1 < 0) ? oImgs.length - 1 : gIndex - 1;        animateSteps(nextIndex, -50);    }    // 向右移动动画    function rightMove(nextIndex) {        if (nextIndex == undefined) {            nextIndex = (gIndex + 1 >= oImgs.length) ? 0 : gIndex + 1;        }        animateSteps(nextIndex, 50);    }    // 一次动画    function animateSteps(nextIndex, timestamp) {        var currentImg = oImgs[gIndex];        var nextImg = oImgs[nextIndex];        nextImg.style.zIndex = 10;        var step = 0;        requestAnimationFrame(goStep);        // 走一帧的动画,移动timestamp        function goStep() {            var moveWidth = timestamp * step++;            if (Math.abs(moveWidth) < imgWidth) {                currentImg.style.transform = `translate(${moveWidth}px)`;                nextImg.style.transform = `translate(${moveWidth > 0 ? (moveWidth - imgWidth) : (imgWidth + moveWidth)}px)`;                requestAnimationFrame(goStep);            } else {                currentImg.style.zIndex = 1;                currentImg.style.transform = `translate(0px)`;                nextImg.style.transform = `translate(0px)`;                oButtons[gIndex].setAttribute('class', '');                oButtons[nextIndex].setAttribute('class', 'active');                gIndex = nextIndex;            }        }    }}window.onclose = function () {    clearTimeout(timeout);}

css布局样式

<style>    /* 首先设置图片box的区域,将图片重叠在一起  */    header {        width: 100%;        position: relative;        overflow: hidden;    }    .box {        width: 100%;        height: 300px;    }    .box img {        width: 100%;        height: 100%;        position: absolute;        transform: translateX(0);        z-index: 1;    }    .box img:first-child {        z-index: 10;    }        /* 数字序列按钮 */    .buttons {        position: absolute;        right: 10%;        bottom: 5%;        display: flex;        z-index: 100;    }    .buttons p {        width: 30px;        height: 30px;        background-color: #aaa;        border: 1px solid #aaa;        text-align: center;        margin: 10px;        cursor: pointer;        opacity: .7;        border-radius: 15px;        line-height: 30px;    }    .buttons p.active {        background-color: white;    }    /* 左右切换按钮 */    .left,    .right {        position: absolute;        width: 80px;        height: 80px;        background-color: #ccc;        z-index: 100;        top: 110px;        border-radius: 40px;        opacity: .5;        cursor: pointer;    }    .left {        left: 2%;    }    .right {        right: 2%;    }    .left .arrow {        width: 30px;        height: 30px;        border-left: solid 5px #666;        border-top: solid 5px #666;        transform: translate(-5px, 25px) rotate(-45deg) translate(25px, 25px);    }    .right .arrow {        width: 30px;        height: 30px;        border-left: solid 5px #666;        border-top: solid 5px #666;        transform: translate(50px, 25px) rotate(135deg) translate(25px, 25px);    }</style>

推荐教程: 《js教程》

微信扫一扫

易采站长站微信账号