## 一、幻燈片的 HTML 和 CSS
```
<div id="slider" class="slider">
<div class="slider-item-container">
<div class="slider-item">
<a href="###" class="slider-link">
<img src="img/1.jpg" alt="slider" class="slider-img">
</a>
</div>
<div class="slider-item">
<a href="###" class="slider-link">
<img src="img/2.jpg" alt="slider" class="slider-img">
</a>
</div>
<div class="slider-item">
<a href="###" class="slider-link">
<img src="img/3.jpg" alt="slider" class="slider-img">
</a>
</div>
<div class="slider-item">
<a href="###" class="slider-link">
<img src="img/4.jpg" alt="slider" class="slider-img">
</a>
</div>
<div class="slider-item">
<a href="###" class="slider-link">
<img src="img/5.jpg" alt="slider" class="slider-img">
</a>
</div>
</div>
<div class="slider-indicator-container">
<span class="slider-indicator"></span>
<span class="slider-indicator"></span>
<span class="slider-indicator"></span>
<span class="slider-indicator"></span>
<span class="slider-indicator"></span>
</div>
</div>
```
```
/*css reset*/
* {
box-sizing: border-box;
padding: 0;
margin: 0;
}
img {
border: none;
vertical-align: top;
}
a {
-webkit-tap-highlight-color: transparent;
}
/*slider*/
.slider {
overflow: hidden;
position: relative;
width: 100%;
height: 183px;
}
.slider-item-container,
.slider-item,
.slider-link,
.slider-img {
width: 100%;
height: 100%;
}
.slider-item-container {
display: flex;
transition: transform 0;
}
.slider-item {
flex-shrink: 0;
}
.slider-link {
display: block;
}
.slider-indicator-container {
position: absolute;
bottom: 10px;
width: 100%;
text-align: center;
}
.slider-indicator {
display: inline-block;
width: 8px;
height: 8px;
background-color: #000;
opacity: 0.2;
border-radius: 50%;
margin-right: 8px;
}
.slider-indicator-active {
background-color: #007aff;
opacity: 1;
}
```
## 二、封裝 Slider.js
```
function Slider(el, options) {
var defaults = {
initIndex: 0,
speed: 300,
hasIndicator: false
};
this.options = {};
this.options.initIndex = typeof options.initIndex !== 'undefined' ? options.initIndex : defaults.initIndex;
this.options.speed = typeof options.speed !== 'undefined' ? options.speed : defaults.speed;
this.options.hasIndicator = typeof options.hasIndicator !== 'undefined' ? options.hasIndicator : defaults.hasIndicator;
this.el = el;
this.itemContainer = el.querySelector('.slider-item-container');
this.items = this.itemContainer.children;
this.distancePerSlide = this.items[0].offsetWidth;
this.minIndex = 0;
this.maxIndex = this.items.length - 1;
// this.index = this.options.initIndex;
this.index = this._adjustIndex(this.options.initIndex);
this.move(this.getDistanceByIndex(this.index));
if (this.options.hasIndicator) {
this._createIndicators();
this._setIndicatorActive(this.index);
}
}
Slider.prototype.to = function (index, cb) {
this.index = index;
this._setTransitionSpeed(this.options.speed);
this.move(this.getDistanceByIndex(this.index));
var self = this;
this.itemContainer.addEventListener('transitionend', function () {
self._setTransitionSpeed(0);
if (typeof cb === 'function') {
cb();
}
}, false);
if (this.options.hasIndicator) {
this._setIndicatorActive(this.index);
}
};
Slider.prototype._setTransitionSpeed = function (speed) {
this.itemContainer.style.transitionDuration = speed + 'ms';
};
Slider.prototype.prev = function (cb) {
this.to(this.index - 1, cb);
};
Slider.prototype.next = function (cb) {
this.to(this.index + 1, cb);
};
Slider.prototype._adjustIndex = function (index) {
if (index < this.minIndex) {
index = this.minIndex;
} else if (index > this.maxIndex) {
index = this.maxIndex;
}
return index;
};
Slider.prototype.move = function (distance) {
this.itemContainer.style.transform = 'translate3d(' + distance + 'px, 0, 0)';
};
Slider.prototype.getDistanceByIndex = function (index) {
return -index * this.distancePerSlide;
};
Slider.prototype._createIndicators = function () {
var indicatorContainer = document.createElement('div');
var html = '';
indicatorContainer.className = 'slider-indicator-container';
for (var i = 0; i <= this.maxIndex; i++) {
html += '<span class="slider-indicator"></span>';
}
indicatorContainer.innerHTML = html;
this.el.appendChild(indicatorContainer);
};
Slider.prototype._setIndicatorActive = function (index) {
this.indicators = this.indicators || this.el.querySelectorAll('.slider-indicator');
for (var i = 0; i < this.indicators.length; i++) {
this.indicators[i].classList.remove('slider-indicator-active');
}
this.indicators[index].classList.add('slider-indicator-active');
};
Slider.prototype.getItemContainer = function () {
return this.itemContainer;
};
Slider.prototype.getIndex = function () {
return this.index;
};
Slider.prototype.getDistancePerSlide = function () {
return this.distancePerSlide;
};
```
## 三、測試 Slider
```
<button id="prev">prev</button>
<button id="next">next</button>
var slider = new Slider(document.getElementById('slider'), {
initIndex: 0, // 初始顯示第幾張幻燈片,從0開始
speed: 300, // 幻燈片的切換速度
hasIndicator: true // 是否需要指示器indicator
});
document.getElementById('prev').addEventListener('click', function () {
// 切換上一張幻燈片
slider.prev();
}, false);
document.getElementById('next').addEventListener('click', function () {
// 切換下一張幻燈片
slider.next();
}, false);
```
## 四、hammer.js
```
var slider = new Slider(document.getElementById('slider'), {
initIndex: 0, // 初始顯示第幾張幻燈片,從0開始
speed: 300, // 幻燈片的切換速度
hasIndicator: true // 是否需要指示器indicator
});
var hammer = new Hammer(slider.getItemContainer());
var isSwiping = false;
hammer.on('panmove', function (ev) {
var distance = ev.deltaX + slider.getDistanceByIndex(slider.getIndex());
slider.move(distance);
});
hammer.on('panend', function (ev) {
if (isSwiping) return;
var distance = ev.deltaX + slider.getDistanceByIndex(slider.getIndex());
var index = getIndexByDistance(distance);
slider.to(index);
});
// 根據容器移動的距離獲取索引
function getIndexByDistance(distance) {
if (distance > 0) {
return 0;
} else {
return Math.round(-distance / slider.getDistancePerSlide());
}
}
hammer.on('swipeleft', function (ev) { // next
isSwiping = true;
slider.next(function () {
isSwiping = false;
});
});
hammer.on('swiperight', function (ev) { // prev
isSwiping = true;
slider.prev(function () {
isSwiping = false;
});
});
```
- 第一章:移動開發入門
- 第一節:概述
- 第二節:基礎概念
- 第一課時:像素
- 第二課時:視口
- 第二章:Flex 布局
- 第一節:概述
- 第二節:容器屬性
- 第一課時:flex-direction 屬性
- 第二課時:flex-wrap 屬性
- 第三課時:flex-flow 屬性
- 第四課時:justify-content 屬性
- 第五課時:align-items 屬性
- 第六課時:align-content 屬性
- 第三節:項目屬性
- 第一課時:order 屬性
- 第二課時:flex-grow 屬性
- 第三課時:flex-shrink 屬性
- 第四課時:flex-basis 屬性
- 第五課時:flex 屬性
- 第六課時:align-self 屬性
- 第四節:Flex 實例
- 第一課時:常見頁面布局
- 第三章:響應式布局
- 第一節:概述
- 第二節:媒體查詢
- 第一課時:概述
- 第二課時:響應式設計
- 第三節:柵格系統
- 第一課時:概述
- 第二課時:案例分析
- 第三課時:Bootstrap 簡介
- 第四節:響應式案例
- 第一課時:三星首頁
- 第四章:移動端適配
- 第五章:移動端事件
- 第一節:概述
- 第二節:touch 事件
- 第三節:觸摸事件對象
- 第四節:其他事件
- 第五節:移動端幻燈片
- 第六章:移動端常見問題
- 第一節:瀏覽器兼容性
- 第二節:移動端動畫
- 第三節:300ms 延遲
- 第四節:文字溢出省略
- 第五節:水平居中和垂直居中
- 第七章:項目案例
- 第一節:美團外賣
- 第一課時:首頁
- 第二課時:訂單頁面
- 第三課時:我的頁面
- 第四課時:詳情頁面
- 第五課時:購物車頁