原生JS利用transform实现banner的无限滚动

更新日期: 2020-05-17 阅读: 2.7k 标签: 滚动

功能


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


原理

首先说下原理。

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

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

动画的实现

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

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


html代码

<header>
    <div class="box">
        <img src="imgs/banner1.jpg">
        <img src="imgs/banner2.jpg">
        <img src="imgs/banner3.jpg">
        <img src="imgs/banner4.jpg">
    </div>
    <div class="buttons">
        <div class="active">1</div>
        <div>2</div>
        <div>3</div>
        <div>4</div>
    </div>
    <div class="left">
        <div class="arrow"></div>
    </div>
    <div class="right">
        <div class="arrow"></div>
    </div>
</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 div');
    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 div {
        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 div.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>
来自:https://segmentfault.com/a/1190000022929832


本文内容仅供个人学习、研究或参考使用,不构成任何形式的决策建议、专业指导或法律依据。未经授权,禁止任何单位或个人以商业售卖、虚假宣传、侵权传播等非学习研究目的使用本文内容。如需分享或转载,请保留原文来源信息,不得篡改、删减内容或侵犯相关权益。感谢您的理解与支持!

链接: https://fly63.com/article/detial/9307

相关推荐

js禁止页面滚动

发移动端页面的时候有一个很比较常见的需求,在出现弹窗时,禁止滑动弹窗后面的主体页面。如何实现呢,往下看

js如何实现滚动到一定位置将内容固定在页面顶部

window.onscroll为滚轮监听,document.body.scrollTop||document.documentElement.scrollTop 写两个是为了兼容不同浏览器。固定位置的top要设为负值,原因不明,若为0则会跟上方有空隙。左右位置虽然是0也要设,不然若为不是100%宽度的内容会出现左右跳动。

js 禁止/允许页面滚动

passive,设置该属性的目的主要是为了在阻止事件默认行为导致的卡顿。等待监听器的执行是耗时的,有些甚至耗时很明显,这样就会导致页面卡顿。即便监听器是个空函数,也会产生一定的卡顿,毕竟空函数的执行也会耗时

js实现返回顶部效果的方法总结

当页面特别长的时候,用户想回到页面顶部,必须得滚动好几次滚动键才能回到顶部,如果在页面右下角有个返回顶部的按钮,用户点击一下,就可以回到顶部,对于用户来说,是一个比较好的体验。

js+css 实现 滚动条滑动时显示,不滑动时隐藏

把原有的滚动条隐藏,创建个新的滚动条,并拓展其宽度,达到隐藏的效果,而判断滚动条是否滚动,保存原有的滚动条到顶部的距离,看是否发生改变,做出相应的判断。

使用elementUI滚动条之横向滚动

这里要简单的设置一下,将标签的height设为100%,读者查看效果的时候,会出现一个横向的滚动条,如果你不想要横向的滚动条,使用下面css属性设置就可以只显示竖向滚动条。

BetterScroll移动端滚动场景的应用

BetterScroll 是一款重点解决移动端各种滚动场景需求的开源插件,有下列功能支持滚动列表,下拉刷新,上拉刷新,轮播图,slider等功能。better-scroll通过使用惯性滚动、边界回弹、滚动条淡入淡出来确保滚动的流畅。

原生js获取浏览器获X轴,Y轴的滚动距离

在前端开发中,需要获取浏览器滚动距离的需求,这篇文章主要讲解如何使用原生Js兼容实现获取浏览器获X轴,Y轴的滚动距离。并延伸扩展下我们一些不知道的js知识,希望对你有所帮助。

CSS让页面平滑滚动

在PC浏览器中,网页默认滚动是在<html>标签上的,移动端大多数在<body>标签上,业界浏览器的CSS reset都可以加上这么一条规则:凡是需要滚动的地方都加一句scroll-behavior:smooth就好了!

原生js判断加载更多事件,通过获取页面滚动距离、文档总高度、浏览器视口高度

原生js获取滚动条在Y轴上的滚动距离、获取文档的总高度、获取浏览器视口的高度的方法实现,用于判断页面加载数据。

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!