兼容:ie9以上
特点:滑动图片看起来永远只有两帧,过度完美;是html css js的完美配合;其中html的data属性起了关键性作用
前提:normalize.css jquery.js
html 代码:
<div class="wrapper"> <div class="carousel" id="carousel-generic"> <!-- Indicators --> <ul class="carousel-indicators"> <li data-slide-to="0" data-target="#carousel-generic" class="active">0</li> <li data-slide-to="1" data-target="#carousel-generic">1</li> <li data-slide-to="2" data-target="#carousel-generic">2</li> </ul> <!-- wrapper for slides --> <div class="carousel-inner"> <div class="item active"> <img alt="first slide" src="images/slide1.png" /> </div> <div class="item"> <img alt="second slide" src="images/slide2.png" /> </div> <div class="item"> <img alt="third slide" src="images/slide3.png" /> </div> </div> <!-- controls --> <a class="carousel-control left" data-slide="prev" href="#carousel-generic"> <span class="carousel-chevron-left"><</span> </a> <a class="carousel-control right" data-slide="next" href="#carousel-generic"> <span class="carousel-chevron-right">></span> </a> </div> </div>
css 代码:
.wrapper{ width:900px; overflow: hidden; margin: 0 auto; } .carousel{ position: relative; width:900px; } .carousel-inner{ position: relative; width: 100%; overflow: hidden; } .carousel-inner .item{ position: relative; display: none; -webkit-transition:0.06s ease-in-out left; -ms-transition: 0.6s ease-in-out left; transition:0.6s ease-in-out left; } .carousel-inner .active, .carousel-inner .next, .carousel-inner .prev{ display: block; } .carousel-inner .active{ left:0; } .carousel-inner .next, .carousel-inner .prev{ position: absolute; top:0; width: 100%; } .carousel-inner .next{ left:100%; } .carousel-inner .prev{ left:-100%; } .carousel-inner .next.left, .carousel-inner .prev.right{ left:0; } .carousel-inner .active.left{ left:-100%; } .carousel-inner .active.right{ left:100%; } .carousel-control { position: absolute; top:0; bottom:0; width:15%; font-size: 20px; color:#fff; text-align: center; text-shadow:0 1px 2px rgba(0, 0, 0, 0.6); opacity: 0.5; } .carousel-control.left { left:0; background-image: -webkit-linear-gradient(left, color-stop(rgba(0, 0, 0, 0.5) 0), color-stop(rgba(0, 0, 0, 0.0001) 100%)); background-image: linear-gradient(to right, rgba(0, 0, 0, 0.5) 0, rgba(0, 0, 0, 0.0001) 100%); background-repeat: repeat-x; } .carousel-control.right { right: 0; left: auto; background-image: -webkit-linear-gradient(left, color-stop(rgba(0, 0, 0, 0.0001) 0), color-stop(rgba(0, 0, 0, 0.5) 100%)); background-image: linear-gradient(to right, rgba(0, 0, 0, 0.0001) 0, rgba(0, 0, 0, 0.5) 100%); background-repeat: repeat-x; } .carousel-control:hover, .carousel-control:focus { color: #ffffff; text-decoration: none; outline: none; opacity: 0.9; } .carousel-indicators{ position: absolute; bottom:10px; width:60%; left:50%; margin-left: -30%; padding-left: 0; text-align: center; z-index: 15; } .carousel-indicators li{ display: inline-block; width: 10px; height: 10px; margin:1px; text-indent: -9999px; line-height: 0; cursor: pointer; background-color: #000 \9; background-color: rgba(0, 0, 0, 0); border:1px solid #fff; border-radius: 10px; } .carousel-indicators .active{ width:12px; height:12px; margin: 0; background-color: #fff; }
js 代码:
(function ($) { "use strict"; var Carousel = function (element, options) { this.$element = $(element); // div.carousel this.$indicators = this.$element.find(".carousel-indicators"); // ul.carousel-indicators this.$items = this.$element.find(".item"); this.paused = false, // 动画停止了?(false) this.sliding = false, // 正在滑动中?(false) this.interval = null, // 有定时器吗?(null) this.$active = null; this.options = options; // 合并后的options this.options.pause === "hover" && this.$element. on("mouseenter", $.proxy(this.pause, this)). on("mouseleave", $.proxy(this.cycle, this)); }; Carousel.DEFAULTS = { interval: 2000, pause: "hover" }; Carousel.fn = Carousel.prototype; Carousel.fn.pause = function () { this.paused = true; // 状态标记 this.interval = clearInterval(this.interval); // this.interval is undefined return this; }; Carousel.fn.cycle = function (e) { e || (this.paused = false); // 标记状态 // 先清除定时器(如果有的话) this.interval && clearInterval(this.interval); // 在重设循环滚动的定时器 this.interval = setInterval($.proxy(this.next, this), this.options.interval); return this; }; Carousel.fn.next = function () { if (this.sliding) { return; } return this.slide("next"); }; Carousel.fn.prev = function () { if (this.sliding) { return; } return this.slide("prev"); }; Carousel.fn.getActiveIndex = function () { this.$active = this.$element.find(".item.active"); return this.$items.index(this.$active); }; // type: ["next", "prev"]; next: targetElement Carousel.fn.slide = function (type, next) { var $active = this.$element.find(".item.active"), $next = next || $active[type](), // 下一帧的目标元素(注:最后一帧的下一帧是第一帧) direction = (type === "next" ? "left" : "right"), fallback = (type === "next" ? "first" : "last"), isCycling = this.interval, that = this; // 边界元素问题 if (!$next.length) { $next = this.$items[fallback](); } if ($next.hasClass('active')) { return false; } // 状态:滚动中。。。 this.sliding = true; // 停止当前动画 isCycling && this.pause(); // 开启新的动画 600毫秒 // o my god!!!!! the sequence is so important, but dont know why!!! $next.addClass(type); $next[0].offsetWidth; // force reflow!!!!!!!!!!!!!! $next.addClass(direction); $active.addClass(direction); // indicator同步改变样式 if (this.$indicators.length) { this.$indicators.find('.active').removeClass('active'); this.$element.one("slide.bs.carousel", function () { // change indicators var $nextIndicator = $(that.$indicators.children()[that.getActiveIndex()]); $nextIndicator && $nextIndicator.addClass("active"); }); } // 动画完成后,重置样式或开启下一帧动画 var transitionend = function () { $next.removeClass([type, direction].join(" ")).addClass("active"); $active.removeClass(["active", direction].join(" ")); // 立即触发 setTimeout(function () { // changer indicators or begin another animation (Carousel.fn.to) that.$element.trigger("slide.bs.carousel"); }, 0); that.sliding = false; isCycling && that.cycle(); }; setTimeout(transitionend, 600); // 时间和css对应 }; // indicator and carousel-control with silde to Carousel.fn.to = function (pos) { var that = this, activeIndex = this.getActiveIndex(); if (pos > (this.$items.length - 1) || pos < 0) { return; } // 运动中。。。。。。。。。 if (this.sliding) { // 当前动画完成后,会立即触发 slide.bs.carousel 事件 return this.$element.one("slide.bs.carousel", function () { that.to(pos); }); } if (activeIndex === pos) { return this.pause().cycle(); } // 通过next或prev的方式到达this.$items[pos] return this.slide(pos > activeIndex ? "next" : "prev", $(this.$items[pos])); }; // jquery 插件 $.fn.carousel = function (option) { return this.each(function () { var $this = $(this), data = $this.data("bs.carsouel"), options = $.extend({}, Carousel.DEFAULTS, typeof option == 'object' && option); if (!data) { // 妙处:把所有方法附加到carousel对象上 ==> $this.data("bs.carousel", (data = new Carousel(this, options))); // $this.data("bs.carousel") = data 就是滚动对象的引用 } if (typeof option === "number") { // 直接切换到第几帧 data.to(option); } else if (typeof option === "string") { data[option](); } else if (options.interval) { // interval is true 则自动播放 data.pause().cycle(); } }); }; $.fn.carousel.Constructor = Carousel; // 事件绑定 $(document).on("click.carousel.data-api", "[data-slide-to], [data-slide]", function (e) { e.preventDefault(); var $this = $(this), $target = $($this.attr("data-target") || $this.attr("href")), slide = $this.attr("data-slide"), slideIndex = $this.attr("data-slide-to"); if (slide) { $target.data("bs.carousel").slide(slide); } else if (slideIndex) { $target.data("bs.carousel").to(slideIndex); } }); // 应用 $(".carousel").carousel(); })(jQuery);