造轮子之 高性能轮播图

实现的功能有(图片看起来有点卡,但事实上是非常非常流畅的轮播图)

无缝轮播。

实现原理:如上图所示,这里有5张图片,而事实上这里有7张图片。在最开头有一张最末尾的图片,在最末尾有一张最开头的图片,所以总共7张图片,队列上就像是这样的 6 - 1 - 2 - 3 - 4 - 5 - 1  排列,当5移向末尾的1时,视觉上就像回到首位的1一样,移动完成时一瞬间把位置移回首位的1即可。

 

相邻效果的跳转

实现原理:如上图所示,有当前图以及目标图,当前图跳到目标图的时候,把除了当前图和目标图以外的所有图都隐藏了,所以就有了相邻效果的跳转。

 

自动轮播

实现原理:js 的定时器。

 

开发的过程

做项目要用到轮播图的时候,我都是用别人造好的轮子,比如著名轮播图插件 swiper 或者 bootstrap 的轮播图插件 ,但我觉得我也能造,所以就立刻行动了起来。

第一个方案其实是用滚动(改变 scrollleft 属性值)的方式进行移动从而实现轮播图的,开发完毕后运行效果非常好,唯一的缺点就是 scrollleft 属性对浮点数的支持不好,会对浮点数进行四舍五入,比如输入23.2px,实际上是23px,这样就损失了0.2px,所以这方案被我搁置了。

第二个方案就从 left 属性 和 transform属性 中选一个了,我选了 transform 属性,无它,就是因为 transform的性能非常强,比left 属性的性能强很多。每次改变 left 属性都会触发回流,而改变 transform 属性并不会触发回流,而且 transform 属性还能强制开启 GPU 加速,使轮播图运行起来非常流畅。

实现动画效果也有两个方案,一个是用 javascript 的定时器,另一个是 css3 的 transition 属性,我选了 transition 属性,无它,css 实现的动画比 js 实现的动画的性能强得多。要实现一次 css 动画,只需改变一次 DOM 属性,而要实现一次 js 动画,要改变很多次 DOM 属性。

综上所述,最后方案选了 translate 属性和 transition 属性开发轮播图。

 

这款轮播图的特点:

1、元素移动主要运用 translate 属性, 动画运用 transition 属性,所以性能非常好,几乎保持60帧(下面图片右上角)。

 

2、强制开始 GPU 加速,并对图层进行了优化,并用上了  will-change 属性,总而言之就是性能非常好。

3、该轮播图的大小有两种设置方式,一种方式是随图片大小,另一种方式是随轮播图的父元素大小。

4、全部代码都用原生 js 进行编写,没有用到任何库(但用到了第三方的字体图标)。

5、因为是面向对象的方式开发的轮播图插件,所以在IE下使用需要把代码转成es5格式,兼容性在谷歌浏览器下完美运行,其他浏览器没测试。

 

在线预览版(可以百度HTML在线运行工具,从中选一个,把下面代码复制进去运行)

<!DOCTYPE html>
<html lang="zh-cn">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="https://cdn.staticfile.org/font-awesome/4.7.0/css/font-awesome.css">
    <style>


        body{
            height: 1000px;
            padding-top: 100px;
        }


        .carousel {
            position: relative;
            display: flex;
            overflow: hidden;
            margin: auto;
        }

        .carousel-inner {
            position: absolute;
            left: 0;
            top:0;
            display: flex;
            z-index: 1;
            will-change: transform;
        }

        .carousel-item {
            margin: 0;
            padding: 0;
        }

        .carousel-item > img {
            /*height: 350px;*/
            /*width: 1400px;*/
            display: block;
        }

        .carousel-control-prev {
            display: flex;
            justify-content: center;
            align-items: center;
            position: absolute;
            height: 30%;
            width: 4%;
            color: rgba(255, 255, 255, 0.8);
            background-color: rgba(0, 0, 0, 0.3);
            font-weight: bold;
            left: 2%;
            top: 50%;
            -webkit-transform: translateY(-50%);
            -ms-transform: translateY(-50%);
            -moz-transform: translateY(-50%);
            -o-transform: translateY(-50%);
            z-index: 2;
        }

        .carousel-control-next {
            display: flex;
            justify-content: center;
            align-items: center;
            position: absolute;
            height: 30%;
            width: 4%;
            color: rgba(255, 255, 255, 0.8);
            background-color: rgba(0, 0, 0, 0.3);
            font-size: 30px;
            font-weight: bold;
            right: 2%;
            top: 50%;
            -webkit-transform: translateY(-50%);
            -ms-transform: translateY(-50%);
            -moz-transform: translateY(-50%);
            -o-transform: translateY(-50%);
            z-index: 2;
        }

        .carousel-control-prev:hover, .carousel-control-next:hover {
            color: #ffffff;
            cursor: pointer;
        }

        .carousel-control-prev > i, .carousel-control-next > i {
            font-size: 50px;
        }


        .carousel-indicators {
            position: absolute;
            display: flex;
            top: 90%;
            left: 50%;
            -webkit-transform: translateX(-50%);
            -ms-transform: translateX(-50%);
            -o-transform: translateX(-50%);
            -moz-transform: translateX(-50%);
            list-style: none;
            padding: 0;
            margin: 0;
            z-index: 2;
        }


        .carousel-indicators > li {
            height: 5px;
            width: 40px;
            background-color: #ffffff;
            opacity: .5;
            margin: 0 8px;
        }

        .carousel-indicators > li:hover {
            cursor: pointer;
            opacity: 1;
        }

        .carousel-indicators .active {
            opacity: 1;
        }
    </style>
</head>
<body>
<div class="carousel">

    <div class="carousel-inner">
        <a class="carousel-item" href="javascript:void(0)">
            <img src="https://static.runoob.com/images/mix/img_fjords_wide.jpg">
        </a>
        <a class="carousel-item active" href="javascript:void(0)">
            <img src="https://static.runoob.com/images/mix/img_nature_wide.jpg">
        </a>
        <a class="carousel-item" href="javascript:void(0)">
            <img src="https://static.runoob.com/images/mix/img_mountains_wide.jpg">
        </a>
    </div>


    <span class="carousel-control-prev" data-slide="prev">
        <i class="fa fa-angle-left"></i>
    </span>
    <span class="carousel-control-next" data-slide="next">
        <i class="fa fa-angle-right"></i>
    </span>


</div>
<div style="margin-top: 30px"><button id="button1" style="margin: 0 10px">停止</button><button id="button2">开始</button></div>
<script>

    window.onload = function () {
        let el1 = document.getElementsByClassName("carousel")[0];
        let carousel1 =  new Carousel({el:el1,autoPlay:true,timingFunction:"ease",duration:500,autoSize:false,autoPlayInterval:2500});
        document.getElementById("button1").onclick = function () {
            carousel1.autoPlayClear();
        };
        document.getElementById("button2").onclick = function () {
            carousel1.autoPlay();
        };

    };

    class Carousel {

        constructor(obj) {

            if(obj.el){
                if(typeof obj.el ==="object"){
                    this.carousel = obj.el;
                }else{
                    throw  new TypeError("el 属性类型错误")
                }
            }else{
                throw  new Error("没找到 el 属性");
            }

            this.isStart = false;
            this.isAutoPlay = false;
            this.isJump = false;
            this.carouselInner = this.carousel.getElementsByClassName("carousel-inner")[0];
            this.carouselItem = this.carouselInner.children;
            const activeObj = this.carouselInner.getElementsByClassName("active")[0];
            this.activeNum = 1;
            let imgArr = this.carouselInner.getElementsByTagName("img");

            if(this.carouselItem.length===0){
                throw  new Error("没有找到轮播图");
            }


            if(obj.duration){
                if(typeof obj.duration ==="number"){
                    this.duration  = obj.duration
                }else{
                    throw new TypeError("duration 属性类型错误")
                }

            }else{
                this.duration = 500;
            }


            if( typeof obj.autoPlayInterval === "number"){
                if(obj.autoPlayInterval <= this.duration){
                    this.autoPlayInterval = this.duration;
                }else{
                    this.autoPlayInterval = obj.autoPlayInterval;
                }
            }else{
                this.autoPlayInterval = 2500;
            }


            if(typeof obj.timingFunction ==="string"){

                switch (obj.timingFunction) {
                    case "linear":
                        this.timingFunction = "linear";
                        break;
                    case "ease":
                        this.timingFunction = "ease";
                        break;
                    case "ease-in":
                        this.timingFunction = "ease-in";
                        break;
                    case "ease-out":
                        this.timingFunction = "ease-out";
                        break;
                    case "ease-in-out":
                        this.timingFunction = "ease-in-out";
                        break;
                    default:
                        throw new TypeError("timingFunction 属性输入错误")
                }


            }else{
                this.timingFunction = "linear";
            }


            for (let i = 0, len = this.carouselItem.length; i < len; i++) {
                if (this.carouselItem[i] === activeObj) {
                    this.activeNum = i + 1;
                }
            }



            let carouselInnerInnerStr = this.carouselItem[this.carouselItem.length-1].outerHTML;
            let carouselIndicatorHTML = "<ul class='carousel-indicators'>";


            for (let i = 0, len = imgArr.length; i < len; i++) {

                this.carouselItem[i].setAttribute("data-slide-index",i+1);
                carouselInnerInnerStr += this.carouselItem[i].outerHTML;

                if (i + 1 === this.activeNum) {
                    carouselIndicatorHTML += "<li class='active' data-slide-to='" + (i + 1) + "'></li>";
                } else {
                    carouselIndicatorHTML += "<li data-slide-to='" + (i + 1) + "'></li>";
                }

            }


            carouselInnerInnerStr += this.carouselItem[0].outerHTML;
            carouselIndicatorHTML += "<ul/>";

            this.carouselInner.innerHTML = carouselInnerInnerStr;

            this.carouselItem[0].classList.remove("active");
            this.carouselItem[this.carouselItem.length-1].classList.remove("active");

            this.carouselItem[0].setAttribute("data-slide-index",0);
            this.carouselItem[this.carouselItem.length-1].setAttribute("data-slide-index",this.carouselItem.length-1);

            this.carousel.insertAdjacentHTML("beforeend", carouselIndicatorHTML);
            this.carouselIndicators = this.carousel.getElementsByClassName("carousel-indicators")[0];
            this.carouselIndicatorsItem = this.carouselIndicators.children;

            if(obj.autoSize === true){
                const height = this.getHeight(this.carousel.parentNode);
                const width = this.getWidth(this.carousel.parentNode);
                this.carousel.style.width = width+"px";
                this.carousel.style.height = height+"px";
                for(let i=0,len=imgArr.length;i<len;i++){
                    imgArr[i].style.height = height+"px";
                    imgArr[i].style.width = width+"px";
                }
            }else{
                this.carousel.style.width = this.getWidth(this.carouselItem[0])+"px";
                this.carousel.style.height =  this.getHeight(this.carouselItem[0])+"px";
            }


            this.offset = this.getWidth(this.carousel);
            this.translate =  -this.offset * (this.activeNum);
            this.carouselInner.style.transform = "translate("+this.translate+"px)";
            const that = this;

            for(let i=0,len = this.carouselIndicatorsItem.length;i<len;i++){
                this.carouselIndicatorsItem[i].onclick = function (e) {
                    that.jump(e);
                }
            }


            this.carousel.getElementsByClassName("carousel-control-prev")[0].onclick = function () {
                that.prev();
            };

            this.carousel.getElementsByClassName("carousel-control-next")[0].onclick = function () {
                that.next();
            };


            if( obj.autoPlay === true){

                this.autoPlay();

            }


        }

        next() {

            if(arguments[0] === true){

                if (this.isStart === true  || this.isJump === true) {
                    return false;
                }

            }else{

                if (this.isStart === true  || this.isAutoPlay === true || this.isJump === true) {
                    return false;
                }
            }


            this.isStart = true;
            const that = this;
            this.activeNum++;

            if(this.carouselInner.style.transition === "" || this.carouselInner.style.transition === "none"){
                this.carouselInner.style.transition  = "transform "+this.duration+"ms "+this.timingFunction;
            }


            if (this.activeNum === this.carouselItem.length - 1) {


                this.carouselIndicatorsItem[this.activeNum - 2].classList.remove("active");
                this.carouselIndicatorsItem[0].classList.add("active");
                this.translate -= that.offset;
                this.carouselInner.style.transform = "translate3d("+this.translate+"px,0px,0px)";

                setTimeout(function () {
                    that.carouselInner.style.transition = "none";
                    that.activeNum = 1;
                    that.translate = -that.offset;
                    that.carouselInner.style.transform = "translate3d("+that.translate+"px,0px,0px)";
                    that.carouselItem[that.carouselItem.length-2].classList.remove("active");
                    that.carouselItem[1].classList.add("active");
                    that.isStart = false;
                },this.duration)


            } else {

                this.carouselIndicatorsItem[this.activeNum - 2].classList.remove("active");
                this.carouselIndicatorsItem[this.activeNum - 1].classList.add("active");
                this.translate -= that.offset;
                this.carouselInner.style.transform = "translate3d("+this.translate+"px,0px,0px)";

                setTimeout(function () {
                    that.carouselItem[that.activeNum - 1].classList.remove("active");
                    that.carouselItem[that.activeNum].classList.add("active");
                    that.isStart = false;
                },this.duration)

            }
        }

        prev(){

            if (this.isStart === true || this.isAutoPlay === true || this.isJump === true) {
                return false;
            }

            this.isStart = true;
            const that = this;
            this.activeNum--;

            if(this.carouselInner.style.transition === "" || this.carouselInner.style.transition === "none"){
                this.carouselInner.style.transition  = "transform "+this.duration+"ms "+this.timingFunction;
            }


            if (this.activeNum === 0) {

                this.carouselIndicatorsItem[this.activeNum].classList.remove("active");
                this.carouselIndicatorsItem[this.carouselItem.length - 3].classList.add("active");
                this.translate += this.offset;
                this.carouselInner.style.transform = "translate3d("+this.translate+"px,0px,0px)";

                setTimeout(function () {
                    that.carouselInner.style.transition = "none";
                    that.activeNum = that.carouselItem.length - 2;
                    that.translate = -that.offset * that.activeNum;
                    that.carouselInner.style.transform = "translate3d("+that.translate+"px,0px,0px)";
                    that.carouselItem[1].classList.remove("active");
                    that.carouselItem[that.carouselItem.length -2].classList.add("active");
                    that.isStart = false;
                },this.duration);


            } else {

                this.carouselIndicatorsItem[this.activeNum].classList.remove("active");
                this.carouselIndicatorsItem[this.activeNum -1].classList.add("active");
                this.translate += this.offset;
                this.carouselInner.style.transform = "translate3d("+this.translate+"px,0px,0px)";

                setTimeout(function () {
                    that.carouselItem[that.activeNum + 1].classList.remove("active");
                    that.carouselItem[that.activeNum].classList.add("active");
                    that.isStart = false;
                },this.duration)


            }
        }


        autoPlay() {

            if(this.isAutoPlay === true){
                return false;
            }

            this.isAutoPlay = true;
            const that = this;
            this.autoPlayId = setInterval(function () {
                that.next(true);
            }, this.autoPlayInterval);

            this.carousel.onmouseenter = function () {
                clearInterval(that.autoPlayId);
                that.isAutoPlay = false;
            };

            this.carousel.onmouseleave = function () {
                that.autoPlay();
            };
        }

        autoPlayClear(){

            if(this.isAutoPlay === false){
                return false;
            }

            this.isAutoPlay = false;
            const that = this;
            clearInterval(that.autoPlayId);
            this.carousel.onmouseenter = function () {};
            this.carousel.onmouseleave = function () {};
        }


        jump(e){

            let target = parseInt(e.target.getAttribute("data-slide-to"));

            if (this.isStart === true || this.isAutoPlay === true || this.isJump === true) {
                return false;
            }

            if (target > this.activeNum) {

                this.isJump = true;

                for (let i = 0, len = this.carouselItem.length; i < len; i++) {

                    if (i !== target && i !== this.activeNum) {
                        this.carouselItem[i].style.display = "none";
                    }

                }

                this.carouselInner.style.left = -this.translate+"px";

                if(this.carouselInner.style.transition === "" || this.carouselInner.style.transition === "none"){
                    this.carouselInner.style.transition  = "transform "+this.duration+"ms "+this.timingFunction;
                }

                const that = this;
                this.carouselIndicatorsItem[this.activeNum - 1].classList.remove("active");
                this.carouselIndicatorsItem[target -1].classList.add("active");
                this.translate -= this.offset;
                this.carouselInner.style.transform = "translate3d("+this.translate+"px,0px,0px)";

                setTimeout(function () {
                    that.carouselInner.style.transition = "none";
                    for (let i = 0, len = that.carouselItem.length; i < len; i++) {
                        that.carouselItem[i].style.display = "block";
                    }
                    that.translate = target* - that.offset;
                    that.carouselInner.style.transform = "translate3d("+that.translate+"px,0px,0px)";
                    that.carouselInner.style.left = "0px";
                    that.carouselItem[that.activeNum].classList.remove("active");
                    that.activeNum = target;
                    that.carouselItem[target].classList.add("active");
                    that.isJump = false
                },this.duration)

            }

            if (target < this.activeNum) {

                this.isJump = true;

                if(this.carouselInner.style.transition === "" || this.carouselInner.style.transition === "none"){
                    this.carouselInner.style.transition  = "transform "+this.duration+"ms "+this.timingFunction;
                }


                for (let i = 0, len = this.carouselItem.length; i < len; i++) {

                    if (i !== target && i !== this.activeNum) {
                        this.carouselItem[i].style.display = "none";
                    }

                }


                this.carouselInner.style.left = (-this.translate)-this.offset+"px";

                if(this.carouselInner.style.transition === "" || this.carouselInner.style.transition === "none"){
                    this.carouselInner.style.transition  = "transform "+this.duration+"ms "+this.timingFunction;
                }


                const that = this;
                this.carouselIndicatorsItem[this.activeNum - 1].classList.remove("active");
                this.carouselIndicatorsItem[target -1].classList.add("active");
                this.translate += this.offset;
                this.carouselInner.style.transform = "translate3d("+this.translate+"px,0px,0px)";

                setTimeout(function () {
                    that.carouselInner.style.transition = "none";
                    for (let i = 0, len = that.carouselItem.length; i < len; i++) {
                        that.carouselItem[i].style.display = "block";
                    }
                    that.translate = target* -that.offset;
                    that.carouselInner.style.transform = "translate3d("+that.translate+"px,0px,0px)";
                    that.carouselInner.style.left = "0px";
                    that.carouselItem[that.activeNum].classList.remove("active");
                    that.activeNum = target;
                    that.carouselItem[target].classList.add("active");
                    that.isJump = false
                },this.duration)
            }
        }


        getWidth(el) {
            const style = window.getComputedStyle ? window.getComputedStyle(el, null) : el.currentStyle;
            let val = parseFloat(style.width);
            let which = ["Left", "Right"];

            if (val === 0) {
                return 0;
            }

            if (style.boxSizing === "content-box") {

                return val;

            }

            if (style.boxSizing === "border-box") {

                for (let i = 0, len = which.length; i < len; i++) {
                    val -= parseFloat(style["border" + which[i] + "Width"]) || 0;
                    val -= parseFloat(style["padding" + which[i]]) || 0;
                }

                return val;
            }

            return false;
        }

        getHeight(el) {
            const style = window.getComputedStyle ? window.getComputedStyle(el, null) : el.currentStyle;
            let val = parseFloat(style.height);
            let which = ["Top", "Bottom"];

            if (val === 0) {
                return 0;
            }

            if (style.boxSizing === "content-box") {

                return val;

            }

            if (style.boxSizing === "border-box") {

                for (let i = 0, len = which.length; i < len; i++) {
                    val -= parseFloat(style["border" + which[i] + "Width"]) || 0;
                    val -= parseFloat(style["padding" + which[i]]) || 0;
                }

                return val;
            }

            return false;
        }

    }

</script>
</body>
</html>

源码:

css 代码

.carousel {
            position: relative;
            display: flex;
            overflow: hidden;
            margin: auto;
        }

        .carousel-inner {
            position: absolute;
            left: 0;
            top:0;
            display: flex;
            z-index: 1;
            will-change: transform;
        }

        .carousel-item {
            margin: 0;
            padding: 0;
        }

        .carousel-item > img {
            display: block;
        }

        .carousel-control-prev {
            display: flex;
            justify-content: center;
            align-items: center;
            position: absolute;
            height: 30%;
            width: 4%;
            color: rgba(255, 255, 255, 0.8);
            background-color: rgba(0, 0, 0, 0.3);
            font-weight: bold;
            left: 2%;
            top: 50%;
            -webkit-transform: translateY(-50%);
            -ms-transform: translateY(-50%);
            -moz-transform: translateY(-50%);
            -o-transform: translateY(-50%);
            z-index: 2;
        }

        .carousel-control-next {
            display: flex;
            justify-content: center;
            align-items: center;
            position: absolute;
            height: 30%;
            width: 4%;
            color: rgba(255, 255, 255, 0.8);
            background-color: rgba(0, 0, 0, 0.3);
            font-size: 30px;
            font-weight: bold;
            right: 2%;
            top: 50%;
            -webkit-transform: translateY(-50%);
            -ms-transform: translateY(-50%);
            -moz-transform: translateY(-50%);
            -o-transform: translateY(-50%);
            z-index: 2;
        }

        .carousel-control-prev:hover, .carousel-control-next:hover {
            color: #ffffff;
            cursor: pointer;
        }

        .carousel-control-prev > i, .carousel-control-next > i {
            font-size: 50px;
        }


        .carousel-indicators {
            position: absolute;
            display: flex;
            top: 90%;
            left: 50%;
            -webkit-transform: translateX(-50%);
            -ms-transform: translateX(-50%);
            -o-transform: translateX(-50%);
            -moz-transform: translateX(-50%);
            list-style: none;
            padding: 0;
            margin: 0;
            z-index: 2;
        }


        .carousel-indicators > li {
            height: 5px;
            width: 40px;
            background-color: #ffffff;
            opacity: .5;
            margin: 0 8px;
        }

        .carousel-indicators > li:hover {
            cursor: pointer;
            opacity: 1;
        }

        .carousel-indicators .active {
            opacity: 1;
        }

js 代码

class Carousel {

    constructor(obj) {

        if(obj.el){
            if(typeof obj.el ==="object"){
                this.carousel = obj.el;
            }else{
                throw  new TypeError("el 属性类型错误")
            }
        }else{
            throw  new Error("没找到 el 属性");
        }


        this.isStart = false;
        this.isAutoPlay = false;
        this.isJump = false;
        this.carouselInner = this.carousel.getElementsByClassName("carousel-inner")[0];
        this.carouselItem = this.carouselInner.children;
        const activeObj = this.carouselInner.getElementsByClassName("active")[0];
        this.activeNum = 1;
        let imgArr = this.carouselInner.getElementsByTagName("img");

        if(this.carouselItem.length===0){
            throw  new Error("没有找到轮播图");
        }


        if(obj.duration){
            if(typeof obj.duration ==="number"){
                this.duration  = obj.duration
            }else{
                throw new TypeError("duration 属性类型错误")
            }

        }else{
            this.duration = 500;
        }


        if( typeof obj.autoPlayInterval === "number"){
            if(obj.autoPlayInterval <= this.duration){
                this.autoPlayInterval = this.duration;
            }else{
                this.autoPlayInterval = obj.autoPlayInterval;
            }
        }else{
            this.autoPlayInterval = 2500;
        }


        if(typeof obj.timingFunction ==="string"){

            switch (obj.timingFunction) {
                case "linear":
                    this.timingFunction = "linear";
                    break;
                case "ease":
                    this.timingFunction = "ease";
                    break;
                case "ease-in":
                    this.timingFunction = "ease-in";
                    break;
                case "ease-out":
                    this.timingFunction = "ease-out";
                    break;
                case "ease-in-out":
                    this.timingFunction = "ease-in-out";
                    break;
                default:
                    throw new TypeError("timingFunction 属性输入错误")
            }


        }else{
            this.timingFunction = "ease";
        }


        for (let i = 0, len = this.carouselItem.length; i < len; i++) {
            if (this.carouselItem[i] === activeObj) {
                this.activeNum = i + 1;
            }
        }



        let carouselInnerInnerStr = this.carouselItem[this.carouselItem.length-1].outerHTML;
        let carouselIndicatorHTML = "<ul class='carousel-indicators'>";


        for (let i = 0, len = imgArr.length; i < len; i++) {

            this.carouselItem[i].setAttribute("data-slide-index",i+1);
            carouselInnerInnerStr += this.carouselItem[i].outerHTML;

            if (i + 1 === this.activeNum) {
                carouselIndicatorHTML += "<li class='active' data-slide-to='" + (i + 1) + "'></li>";
            } else {
                carouselIndicatorHTML += "<li data-slide-to='" + (i + 1) + "'></li>";
            }

        }


        carouselInnerInnerStr += this.carouselItem[0].outerHTML;
        carouselIndicatorHTML += "<ul/>";

        this.carouselInner.innerHTML = carouselInnerInnerStr;

        this.carouselItem[0].classList.remove("active");
        this.carouselItem[this.carouselItem.length-1].classList.remove("active");

        this.carouselItem[0].setAttribute("data-slide-index",0);
        this.carouselItem[this.carouselItem.length-1].setAttribute("data-slide-index",this.carouselItem.length-1);

        this.carousel.insertAdjacentHTML("beforeend", carouselIndicatorHTML);
        this.carouselIndicators = this.carousel.getElementsByClassName("carousel-indicators")[0];
        this.carouselIndicatorsItem = this.carouselIndicators.children;

        if(obj.autoSize === true){
            const height = this.getHeight(this.carousel.parentNode);
            const width = this.getWidth(this.carousel.parentNode);
            this.carousel.style.width = width+"px";
            this.carousel.style.height = height+"px";
            for(let i=0,len=imgArr.length;i<len;i++){
                imgArr[i].style.height = height+"px";
                imgArr[i].style.width = width+"px";
            }
        }else{
            this.carousel.style.width = this.getWidth(this.carouselItem[0])+"px";
            this.carousel.style.height =  this.getHeight(this.carouselItem[0])+"px";
        }


        this.offset = this.getWidth(this.carousel);
        this.translate =  -this.offset * (this.activeNum);
        this.carouselInner.style.transform = "translate("+this.translate+"px)";
        const that = this;

        for(let i=0,len = this.carouselIndicatorsItem.length;i<len;i++){
            this.carouselIndicatorsItem[i].onclick = function (e) {
                that.jump(e);
            }
        }


        this.carousel.getElementsByClassName("carousel-control-prev")[0].onclick = function () {
            that.prev();
        };

        this.carousel.getElementsByClassName("carousel-control-next")[0].onclick = function () {
            that.next();
        };


        if( obj.autoPlay === true){

            this.autoPlay();

        }


    }

    next() {

        if(arguments[0] === true){

            if (this.isStart === true  || this.isJump === true) {
                return false;
            }

        }else{

            if (this.isStart === true  || this.isAutoPlay === true || this.isJump === true) {
                return false;
            }
        }


        this.isStart = true;
        const that = this;
        this.activeNum++;

        if(this.carouselInner.style.transition === "" || this.carouselInner.style.transition === "none"){
            this.carouselInner.style.transition  = "transform "+this.duration+"ms "+this.timingFunction;
        }


        if (this.activeNum === this.carouselItem.length - 1) {


            this.carouselIndicatorsItem[this.activeNum - 2].classList.remove("active");
            this.carouselIndicatorsItem[0].classList.add("active");
            this.translate -= that.offset;
            this.carouselInner.style.transform = "translate3d("+this.translate+"px,0px,0px)";

            setTimeout(function () {
                that.carouselInner.style.transition = "none";
                that.activeNum = 1;
                that.translate = -that.offset;
                that.carouselInner.style.transform = "translate3d("+that.translate+"px,0px,0px)";
                that.carouselItem[that.carouselItem.length-2].classList.remove("active");
                that.carouselItem[1].classList.add("active");
                that.isStart = false;
            },this.duration)


        } else {

            this.carouselIndicatorsItem[this.activeNum - 2].classList.remove("active");
            this.carouselIndicatorsItem[this.activeNum - 1].classList.add("active");
            this.translate -= that.offset;
            this.carouselInner.style.transform = "translate3d("+this.translate+"px,0px,0px)";

            setTimeout(function () {
                that.carouselItem[that.activeNum - 1].classList.remove("active");
                that.carouselItem[that.activeNum].classList.add("active");
                that.isStart = false;
            },this.duration)

        }
    }

    prev(){

        if (this.isStart === true || this.isAutoPlay === true || this.isJump === true) {
            return false;
        }

        this.isStart = true;
        const that = this;
        this.activeNum--;

        if(this.carouselInner.style.transition === "" || this.carouselInner.style.transition === "none"){
            this.carouselInner.style.transition  = "transform "+this.duration+"ms "+this.timingFunction;
        }


        if (this.activeNum === 0) {

            this.carouselIndicatorsItem[this.activeNum].classList.remove("active");
            this.carouselIndicatorsItem[this.carouselItem.length - 3].classList.add("active");
            this.translate += this.offset;
            this.carouselInner.style.transform = "translate3d("+this.translate+"px,0px,0px)";

            setTimeout(function () {
                that.carouselInner.style.transition = "none";
                that.activeNum = that.carouselItem.length - 2;
                that.translate = -that.offset * that.activeNum;
                that.carouselInner.style.transform = "translate3d("+that.translate+"px,0px,0px)";
                that.carouselItem[1].classList.remove("active");
                that.carouselItem[that.carouselItem.length -2].classList.add("active");
                that.isStart = false;
            },this.duration);


        } else {

            this.carouselIndicatorsItem[this.activeNum].classList.remove("active");
            this.carouselIndicatorsItem[this.activeNum -1].classList.add("active");
            this.translate += this.offset;
            this.carouselInner.style.transform = "translate3d("+this.translate+"px,0px,0px)";

            setTimeout(function () {
                that.carouselItem[that.activeNum + 1].classList.remove("active");
                that.carouselItem[that.activeNum].classList.add("active");
                that.isStart = false;
            },this.duration)


        }
    }


    autoPlay() {

        if(this.isAutoPlay === true){
            return false;
        }

        this.isAutoPlay = true;
        const that = this;
        this.autoPlayId = setInterval(function () {
            that.next(true);
        }, this.autoPlayInterval);

        this.carousel.onmouseenter = function () {
            clearInterval(that.autoPlayId);
            that.isAutoPlay = false;
        };

        this.carousel.onmouseleave = function () {
            that.autoPlay();
        };
    }

    autoPlayClear(){

        if(this.isAutoPlay === false){
            return false;
        }

        this.isAutoPlay = false;
        const that = this;
        clearInterval(that.autoPlayId);
        this.carousel.onmouseenter = function () {};
        this.carousel.onmouseleave = function () {};
    }


    jump(e){

        let target = parseInt(e.target.getAttribute("data-slide-to"));

        if (this.isStart === true || this.isAutoPlay === true || this.isJump === true) {
            return false;
        }

        if (target > this.activeNum) {

            this.isJump = true;

            for (let i = 0, len = this.carouselItem.length; i < len; i++) {

                if (i !== target && i !== this.activeNum) {
                    this.carouselItem[i].style.display = "none";
                }

            }

            this.carouselInner.style.left = -this.translate+"px";

            if(this.carouselInner.style.transition === "" || this.carouselInner.style.transition === "none"){
                this.carouselInner.style.transition  = "transform "+this.duration+"ms "+this.timingFunction;
            }

            const that = this;
            this.carouselIndicatorsItem[this.activeNum - 1].classList.remove("active");
            this.carouselIndicatorsItem[target -1].classList.add("active");
            this.translate -= this.offset;
            this.carouselInner.style.transform = "translate3d("+this.translate+"px,0px,0px)";

            setTimeout(function () {
                that.carouselInner.style.transition = "none";
                for (let i = 0, len = that.carouselItem.length; i < len; i++) {
                    that.carouselItem[i].style.display = "block";
                }
                that.translate = target* - that.offset;
                that.carouselInner.style.transform = "translate3d("+that.translate+"px,0px,0px)";
                that.carouselInner.style.left = "0px";
                that.carouselItem[that.activeNum].classList.remove("active");
                that.activeNum = target;
                that.carouselItem[target].classList.add("active");
                that.isJump = false
            },this.duration)

        }

        if (target < this.activeNum) {

            this.isJump = true;

            if(this.carouselInner.style.transition === "" || this.carouselInner.style.transition === "none"){
                this.carouselInner.style.transition  = "transform "+this.duration+"ms "+this.timingFunction;
            }


            for (let i = 0, len = this.carouselItem.length; i < len; i++) {

                if (i !== target && i !== this.activeNum) {
                    this.carouselItem[i].style.display = "none";
                }

            }


            this.carouselInner.style.left = (-this.translate)-this.offset+"px";

            if(this.carouselInner.style.transition === "" || this.carouselInner.style.transition === "none"){
                this.carouselInner.style.transition  = "transform "+this.duration+"ms "+this.timingFunction;
            }


            const that = this;
            this.carouselIndicatorsItem[this.activeNum - 1].classList.remove("active");
            this.carouselIndicatorsItem[target -1].classList.add("active");
            this.translate += this.offset;
            this.carouselInner.style.transform = "translate3d("+this.translate+"px,0px,0px)";

            setTimeout(function () {
                that.carouselInner.style.transition = "none";
                for (let i = 0, len = that.carouselItem.length; i < len; i++) {
                    that.carouselItem[i].style.display = "block";
                }
                that.translate = target* -that.offset;
                that.carouselInner.style.transform = "translate3d("+that.translate+"px,0px,0px)";
                that.carouselInner.style.left = "0px";
                that.carouselItem[that.activeNum].classList.remove("active");
                that.activeNum = target;
                that.carouselItem[target].classList.add("active");
                that.isJump = false
            },this.duration)
        }
    }


    getWidth(el) {
        const style = window.getComputedStyle ? window.getComputedStyle(el, null) : el.currentStyle;
        let val = parseFloat(style.width);
        let which = ["Left", "Right"];

        if (val === 0) {
            return 0;
        }

        if (style.boxSizing === "content-box") {

            return val;

        }

        if (style.boxSizing === "border-box") {

            for (let i = 0, len = which.length; i < len; i++) {
                val -= parseFloat(style["border" + which[i] + "Width"]) || 0;
                val -= parseFloat(style["padding" + which[i]]) || 0;
            }

            return val;
        }

        return false;
    }

    getHeight(el) {
        const style = window.getComputedStyle ? window.getComputedStyle(el, null) : el.currentStyle;
        let val = parseFloat(style.height);
        let which = ["Top", "Bottom"];

        if (val === 0) {
            return 0;
        }

        if (style.boxSizing === "content-box") {

            return val;

        }

        if (style.boxSizing === "border-box") {

            for (let i = 0, len = which.length; i < len; i++) {
                val -= parseFloat(style["border" + which[i] + "Width"]) || 0;
                val -= parseFloat(style["padding" + which[i]]) || 0;
            }

            return val;
        }

        return false;
    }

}

源码下载

https://gitee.com/island_tears/carousel

使用说明

1、引入字体图标文件,cdn地址:https://cdn.staticfile.org/font-awesome/4.7.0/css/font-awesome.css

2、引入 carousel.css 文件。

3、引入 carousel.js 文件。

4、复制轮播图 HTML 代码(如下)到需要用到的地方,a 标签可以改成其它标签,href 属性 和 src 属性改成实际的值。

<div class="carousel">

    <div class="carousel-inner">
        <a class="carousel-item" href="javascript:void(0)">
            <img src="https://static.runoob.com/images/mix/img_fjords_wide.jpg">
        </a>
        <a class="carousel-item active" href="javascript:void(0)">
            <img src="https://static.runoob.com/images/mix/img_nature_wide.jpg">
        </a>
        <a class="carousel-item" href="javascript:void(0)">
            <img src="https://static.runoob.com/images/mix/img_mountains_wide.jpg">
        </a>
    </div>

    <span class="carousel-control-prev">
        <i class="fa fa-angle-left"></i>
    </span>
    <span class="carousel-control-next">
        <i class="fa fa-angle-right"></i>
    </span>
    
</div>

5、实例化 Carousel 对象, Carousel 对象必须接受一个匿名对象作为参数。

该匿名对象所有属性的作用如下

el 属性:HTML 对象(就是上面的 class = "carousel" ),不能为空。

autoPlay 属性:是否开启自动轮播,取值为布尔类型,true 开启,false 不开启,默认为 false。

timingFunction 属性:为轮播图滑动时的动画曲线,取值为字符串类型,取值范围和 css3 的 transition-timing-function 属性 取值范围一样。默认为 ease。

duration 属性:轮播图切换时花费的时间,取值为数字类型,单位为毫秒,默认为500毫秒。

autoSize 属性:轮播图大小是否取决于父元素,取值为布尔类型,true 轮播图大小取决于父元素,false 轮播图大小取决于图片大小,默认为 false。

autoPlayInterval 属性:自动轮播的间隔时间,取值为数字类型,单位为毫秒,默认为2500毫秒。

Carousel 实例有2个方法

autoPlayClear 方法:清除自动轮播。

autoPlay 方法:开启自动轮播。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值