<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>珠峰培训</title>
<link rel="stylesheet" href="css/reset.min.css">
<link rel="stylesheet" href="css/banner-fade.css">
</head>
<body>
<section class="container" id="container">
<div class="wrapper">
<!--<div class="slide"><img src="img/banner1.jpg" alt=""></div>
<div class="slide"><img src="img/banner2.jpg" alt=""></div>
<div class="slide"><img src="img/banner3.jpg" alt=""></div>
<div class="slide"><img src="img/banner4.jpg" alt=""></div>-->
</div>
<ul class="focus">
<!--<li class="active"></li>
<li></li>
<li></li>
<li></li>-->
</ul>
<a href="javascript:;" class="arrow arrowLeft"></a>
<a href="javascript:;" class="arrow arrowRight"></a>
</section>
<script src="js/jquery-1.11.3.min.js"></script>
<script src="js/banner-fade.js"></script>
</body>
</html>
.container {
position: relative;
margin: 20px auto;
width: 1000px;
height: 300px;
overflow: hidden;
}
.container .wrapper {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
.container .wrapper .slide {
position: absolute;
top: 0;
left: 0;
z-index: 0;
opacity: 0;
width: 100%;
height: 100%;
overflow: hidden;
}
/*默认展示第一个*/
.container .wrapper .slide:nth-of-type(1) {
z-index: 1;
opacity: 1;
}
.container .wrapper .slide img {
display: block;
width: 100%;
height: 100%;
}
.container .focus {
position: absolute;
z-index: 999;
bottom: 10px;
left: 50%;
transform: translateX(-50%);
padding: 4px;
height: 12px;
background: rgba(0, 0, 0, .5);
border-radius: 10px;
font-size: 0;
}
.container .focus li {
display: inline-block;
margin: 0 4px;
width: 12px;
height: 12px;
border-radius: 50%;
background: #FFF;
cursor: pointer;
}
.container .focus li.active {
background: #DB192A;
}
.container .arrow {
display: none;
position: absolute;
top: 50%;
z-index: 999;
margin-top: -22.5px;
width: 28px;
height: 45px;
background: url("../img/pre.png") no-repeat;
opacity: 0.3;
}
.container .arrow:hover {
opacity: 1;
}
.container .arrow.arrowLeft {
left: 0;
background-position: 0 0;
}
.container .arrow.arrowRight {
right: 0;
background-position: -50px 0;
}
$(function () {
let bannerRender = (function anonymous() {
let $container = $('#container'),
$wrapper = $container.children('.wrapper'),
$focus = $container.children('.focus'),
$arrowLeft = $container.children('.arrowLeft'),
$arrowRight = $container.children('.arrowRight'),
$slideList = null,
$focusList = null;
//=>QUERY-DATA:获取数据
let queryData = function queryData() {
return new Promise((resolve, reject) => {
$.ajax({
url: 'json/banner.json',//=>请求API地址
method: 'get',//=>请求方式
dataType: 'json',//=>把获取的JSON字符串转为对象
async: true,//=>TRUE:异步 FALSE:同步
success: resolve,
error: reject
/*success: data => {
//=>成功后执行的回调函数,DATA从服务器端获取的数据(对象)
resolve(data);
},
error: msg => {
//=>失败后执行的回调函数,MSG存储了失败的信息
reject(msg);
}*/
});
});
};
//=>BIND-HTML:数据绑定
let bindHTML = function bindHTML(data) {
let strSlide = ``,
strFocus = ``;
$.each(data, (index, item) => {
let {img, desc} = item;
strSlide += `<div class="slide">
<img src="${img}" alt="${desc}">
</div>`;
strFocus += `<li class="${index === 0 ? 'active' : ''}"></li>`;
});
$wrapper.html(strSlide);
$focus.html(strFocus);
$slideList = $wrapper.find('.slide');
$focusList = $focus.find('li');
};
//=>SLIDE切换的公共方法
let changeSlide = function changeSlide() {
/*
* 切换思路:
* 1.让当前的Z-INDEX=1,并且让上一个的Z-INDEX=0(这样是为了保证不管结构是靠前还是靠后,始终当前这个都是层级最高的,也是优先展示的)
* 2.让当前的实现出渐现的效果(OPACITY从0~1)
* 3.当前这个已经渐现出来(动画结束),我们再让上一个透明度为零(为了下一次展示它的时候,透明度是从零开始渐现的)
* 4.让当前的索引变为下一次对应的上一次索引
*/
let $cur = $slideList.eq(_index),
$last = $slideList.eq(_lastIndex);
$cur.css('zIndex', 1);
$last.css('zIndex', 0);
$cur.stop().animate({
opacity: 1
}, _speed, () => {
$last.css({opacity: 0});
_lastIndex = _index;
});
changeFocus();
};
//=>AUTO-MOVE:自动轮播
let _index = 0,//=>当前展示SLIDE的索引
_lastIndex = 0,//=>上一次展示SLIDE的索引
_timer = null,//=>存储自动轮播的定时器
_interval = 3000,//=>多久切换一次
_speed = 200;//=>每一次切换动画的时间
let autoMove = function autoMove() {
_index++;
//=>边界判断:如果累加的结果大于最大索引,我们展示第一个SLIDE即可
if (_index >= $slideList.length) {
_index = 0;
}
changeSlide();
};
//=>CHANGE-FOCUS:焦点对齐
let changeFocus = function changeFocus() {
$focusList.eq(_index).addClass('active');
$focusList.eq(_lastIndex).removeClass('active');
};
//=>HANDLE-MOUSE:鼠标控制暂停和开启
let handleMouse = function handleMouse() {
$container.on('mouseenter', () => {
clearInterval(_timer);
$arrowLeft.add($arrowRight).css('display', 'block');//=>ADD:是在一个JQ集合中增加一些新的元素(获取新的JQ对象),有点类似乎两个集合合并
}).on('mouseleave', () => {
_timer = setInterval(autoMove, _interval);
$arrowLeft.add($arrowRight).css('display', 'none');
})
};
//=>HANDLE-ARROW:箭头左右切换
let handleArrow = function handleArrow() {
$arrowRight.on('click', autoMove);
$arrowLeft.on('click', () => {
_index--;
if (_index < 0) {
_index = $slideList.length - 1;
}
changeSlide();
});
};
//=>HANDLE-FOCUS:点击焦点切换
let handleFocus = function handleFocus() {
$focusList.on('click', function anonymous() {
let curIndex = $(this).index();
if (_index === curIndex) {
//=>当前展示的和点击的是同一个,不做任何的处理
return;
}
_index = curIndex;
changeSlide();
});
};
return {
init: function init() {
let promise = queryData();
promise.then(data => {
//=>获取数据成功后处理的事情(DATA就是获取的数据)
bindHTML(data);
_timer = setInterval(autoMove, _interval);
handleMouse();
handleArrow();
handleFocus();
});
}
}
})();
bannerRender.init();
});
插件封装 banner-plugin.js
* 封装插件
* 1. 每一次调用插件都是独立的,互不影响的
*
* 2. 一些常用的方法还要是公用的
*
* 调取一次插件就是创建一个独立的实例,里面的很多信息是互相不干扰的,但是对于一些操作操作方法还是共同调取一个即可(这套机制就是我们的构造函数模式中类和实例的机制),所以插件、组件、类库、框架的封装一般都是基于OOP面向对象完成的
*
* 3. 封装插件的目的是:可以更多适配各种需求、让用户使用起来非常的方便,所以插件封装的核心和难点都在于细节的思考和处理,而不应该局限到各种模式或者装X的代码中
//=>一个优秀的插件是尽可能支持更多的配置项(大部分配置项都是有默认值的)
// new Banner({
// ele: '#container', //=>操作哪个容器(选择器)
// // data: [], //=>需要绑定的数据
// url: '',//=>获取数据的API地址(插件内部帮我们获取数据)
// isArrow: true,//=>是否支持左右切换
// isFocus: true,//=>是否支持焦点切换
// isAuto: true,//=>是否支持自动切换
// defaultIndex: 0,//=>默认展示第几张
// interval: 3000,//=>多久切换一次
// speed: 200,//=>切换的速度
// moveEnd:()=>{},//=>切换完成后处理的事情
// ...
// });
//=>支持扩展,可以让用户自己在你的插件中扩展方法
// Banner.fn.extend({xxx:()=>{}})
// ...
~function () {
class Banner {
constructor(options = {}) {
//=>OPTIONS传递的配置项(解构赋值并且给更多的配置项设置默认值)
let {
ele,
url,
isArrow = true,
isFocus = true,
isAuto = true,
defaultIndex = 0,
interval = 3000,
speed = 200,
moveEnd
} = options;
//=>把所有的配置项信息都挂载到实例上(这样以后在原型的任何方法中都可以调取这些属性获取值了)
['ele', 'url', 'isArrow', 'isFocus', 'isAuto', 'defaultIndex', 'interval', 'speed', 'moveEnd'].forEach(item => {
this[item] = eval(item);
});
this.container = document.querySelector(ele);
let _con = this.container;
this.wrapper = _con.querySelector('.wrapper');
this.focus = _con.querySelector('.focus');
this.arrowLeft = _con.querySelector('.arrowLeft');
this.arrowRight = _con.querySelector('.arrowRight');
this.slideList = null;
this.focusList = null;
this.stepIndex = defaultIndex;
this.autoTimer = null;
//=>调取INIT开启轮播图
this.init();
}
//=>BANNER的主入口(在INIT中规划方法的执行顺序)
init() {
let {isAuto, interval} = this;
let promise = this.queryData();
promise.then(() => {
this.bindHTML();
}).then(() => {
if (isAuto) {
this.autoTimer = setInterval(() => {
this.autoMove();
}, interval);
}
});
}
//=>获取数据(PROMISE)
queryData() {
let {url} = this;
return new Promise((resolve, reject) => {
let xhr = new XMLHttpRequest;
xhr.open('GET', url);
xhr.onreadystatechange = () => {
if (xhr.readyState === 4 && xhr.status === 200) {
//=>把获取的数据也挂载到实例上了
this.data = JSON.parse(xhr.responseText);
resolve();
}
};
xhr.send(null);
});
}
//=>数据绑定
bindHTML() {
//属性可以结构,方法不可以
let {data, wrapper, focus, slideList, focusList} = this;
let strSlide = ``,
strFocus = ``;
data.forEach((item, index) => {
let {img = 'img/banner1.jpg', desc = '珠峰培训'} = item;
strSlide += `<div class="slide">
<img src="${img}" alt="${desc}">
</div>`;
strFocus += `<li class="${index === 0 ? 'active' : ''}"></li>`;
});
wrapper.innerHTML = strSlide;
focus.innerHTML = strFocus;
//->获取所有的SLIDE和LI
this.slideList = wrapper.querySelectorAll('.slide');
this.focusList = focus.querySelectorAll('li');
wrapper.appendChild(this.slideList[0].cloneNode(true));
this.slideList =wrapper.querySelectorAll('.slide');
utils.css(wrapper, 'width', this.slideList.length * 1000);
};
//=>自动轮播
autoMove() {
this.stepIndex++;
if (this.stepIndex >= this.slideList.length) {
utils.css(this.wrapper, 'left', 0);
this.stepIndex = 1;
}
//->基于自主封装的ANIMATE实现切换动画
animate(this.wrapper, {
left: -this.stepIndex * 1000
}, this.speed);
this.changeFocus();
};
changeFocus() {
let tempIndex = this.stepIndex;
tempIndex === this.slideList.length - 1 ? tempIndex = 0 : null;
[].forEach.call(this.focusList, (item, index) => {
item.className = index === tempIndex ? 'active' : '';
});
};
}
window.Banner = Banner;
}();