实现的功能有(图片看起来有点卡,但事实上是非常非常流畅的轮播图)
无缝轮播。
实现原理:如上图所示,这里有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 方法:开启自动轮播。