學(xué)習(xí)了許多的javascript知識(shí),我們今天來(lái)做一個(gè)應(yīng)用—輪播圖。許多網(wǎng)站上都有輪播圖,像淘寶,京東等電商網(wǎng)站的首頁(yè),輪播圖總是不可獲取的頁(yè)面組成元素。往往大家都是上網(wǎng)找插件(最出名的可能是swiper)。假如自己動(dòng)手讓你用原生js寫(xiě)一個(gè)呢?
下面我們開(kāi)始今天的主題,一個(gè)可自動(dòng)輪播+點(diǎn)擊輪播+無(wú)縫滾動(dòng)的原生輪播圖。
上代碼:
css部分
// 樣式重置
* {
margin: 0;
padding: 0;
list-style: none;
}
// 主要樣式
// 大盒子
.box{
width: 560px;
height: 300px;
position: relative;
overflow: hidden;
border: 1px solid #f00;
margin: 30px auto;
box-shadow: 1px 1px 10px 5px blue;
}
// 包裹圖片的盒子,這樣做是為了無(wú)縫滾動(dòng)服務(wù)
.wrap{
position: relative;
width: 5000px;
height: 300px;
top: 0;
left: 0px;
}
// 圖片盒子
.wrap ul{
position: absolute;
top: 0;
left: 0;
}
.wrap ul li{
float: left;
}
// 控制圓點(diǎn)盒子
.control{
position: absolute;
bottom: 5px;
right: 0;
}
// 控制圓點(diǎn)設(shè)置
.control li{
margin-right: 5px;
width: 20px;
height: 20px;
line-height: 20px;
font-weight: bold;
text-align: center;
background: #fff;
cursor: pointer;
border-radius: 50%;
float: left;
}
// 選中狀態(tài)
.control li.active{
background: red;
color: #fff;
}
// 按鈕盒子
.btn{
position: absolute;
width: 100%;
top: 50%;
margin-top: -25px;
}
// 按鈕樣式
.btn a{
width: 50px;
height: 50px;
line-height: 45px;
text-decoration-line: none;
color: aliceblue;
font-size: 36px;
background: rgba(0, 0, 0, .5);
text-align: center;
border-radius: 50%;
opacity: .5;
display: none;
}
.btn .prev{
float: left;
}
.btn .next{
float: right;
}
// 滑入選中狀態(tài)
.btn .prev:hover,
.btn .next:hover {
filter: alpha(opacity=100);
opacity: 1;
}
css部分需要注意的是我們要做無(wú)縫滾動(dòng)的效果所以我們的大盒子 wrap 要寬度足夠才能讓每一張圖片排成一排,因?yàn)槲覀兪冀K動(dòng)的只是包裹圖片的 ul。
接下來(lái)是html:
<div class="box" id="wrap">
<div class="wrap" >
<ul id="imgBox"></ul>
</div>
<ul class="control" id="control"></ul>
<div class="btn">
<a href="javascript:;" class="prev"><</a>
<a href="javascript:;" class="next">></a>
</div>
</div>
布局這方面沒(méi)啥說(shuō)的,因?yàn)槭莿?dòng)態(tài)生成圖片和控制圓點(diǎn),所以沒(méi)有直接寫(xiě) li。
下面主要的來(lái)了
js部分:
// 元素獲取
var wrap = document.getElementById("wrap")
var imgBox = document.getElementById("imgBox");
var control = document.getElementById("control");
var prev = document.getElementsByTagName("a")[0];
var next = document.getElementsByTagName("a")[1];
var imgWidth = 560;
var target = 0;
var imgIndex = 0;
var timer = null;
var autoTimer = null;
// ------------------------start--------------------
var imgs = [
'img/0.jpg',
'img/1.jpg',
'img/2.jpg',
'img/3.jpg',
'img/4.jpg'
]
var lis = []; // 圖片列表數(shù)組
var ctrs = [];// 控制點(diǎn)數(shù)組
// 動(dòng)態(tài)創(chuàng)建圖片列表
for (let index = 0; index < imgs.length; index++) {
lis.push('<li><img src="'+imgs[index]+'" /></li>')
ctrs.push('<li>'+(index-1+2)+'</li>')
}
// 加入到頁(yè)面中
imgBox.innerHTML = lis.join("");
// 復(fù)制節(jié)點(diǎn)
imgBox.appendChild(imgBox.children[0].cloneNode(true));
control.innerHTML = ctrs.join("");
control.children[0].setAttribute("class","active");
//---------------------------------------------------
//按鈕顯示隱藏
wrap.onmouseover = function () {
prev.style.display = "block";
next.style.display = "block";
clearInterval(autoTimer);// 清除自動(dòng)輪播
}
wrap.onmouseout = function () {
prev.style.display = "none";
next.style.display = "none";
autoPlay();// 開(kāi)啟自動(dòng)輪播
}
// 控制點(diǎn)循環(huán)綁定事件
var ctrlis = control.getElementsByTagName("li");
for (let i = 0; i < ctrlis.length; i++) {
ctrlis[i].index = i;// 記錄元素
ctrlis[i].onmouseover = function(){
// clearInterval(timer);
imgIndex = this.index;
animate(imgIndex);
}
}
// 上一頁(yè)
prev.onclick = function(){
clearInterval(timer);// 清除運(yùn)動(dòng)定時(shí)器
imgIndex--;
if (imgIndex == -1) {
imgBox.style.left = -imgWidth*(imgBox.children.length-1) + "px";
imgIndex = imgBox.children.length-2;
}
animate(imgIndex);
}
// 下一頁(yè)
next.onclick = function(){
clearInterval(timer);
imgIndex++;
if (imgIndex == imgBox.children.length) {
imgBox.style.left = 0;
imgIndex = 1;
}
animate(imgIndex);
}
// 運(yùn)動(dòng)封裝
function animate(index){
clearInterval(timer);
// 控制點(diǎn)樣式修改
for(let i = 0; i < ctrlis.length; i++){
ctrlis[i].className = "";
}
ctrlis[index%ctrlis.length].className="active"
//開(kāi)啟定時(shí)器
timer = setInterval(function(){
target = -index*imgWidth; // 目標(biāo)距離
var step = 210/30;// 運(yùn)動(dòng)次數(shù) 這個(gè)可以設(shè)置參數(shù)傳入,像index一樣,后面再加一位參數(shù),這里就寫(xiě)死了
let speed = (target - imgBox.offsetLeft)/step // 每次步長(zhǎng)是由目標(biāo)距離減去當(dāng)前距離
speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed); // 取整方便計(jì)算
if (target == imgBox.offsetLeft) {
clearInterval(timer);// 到達(dá)終點(diǎn),我們要停止運(yùn)動(dòng)
}else{
imgBox.style.left = imgBox.offsetLeft + speed + "px";// 這是left值
}
},30);
}
// 自動(dòng)輪播
function autoPlay() {
autoTimer = setInterval(function(){
// 這個(gè)邏輯和下一頁(yè)點(diǎn)擊的邏輯相同
imgIndex++;
if (imgIndex == imgBox.children.length) {
imgBox.style.left = 0;
imgIndex = 1;
}
animate(imgIndex);
},2000)
}
autoPlay() // 開(kāi)始自動(dòng)輪播
這塊的js都是基礎(chǔ)知識(shí)的組裝,所以js基礎(chǔ)還是很重要的。
我們來(lái)講一下重點(diǎn):
- 標(biāo)簽的創(chuàng)建與添加,還有克隆, 用到了字符串拼接的方法,innerHtML、 appendChild()、cloneNode()。標(biāo)簽用字符串創(chuàng)建出來(lái)放進(jìn)數(shù)組,然后join(),是一個(gè)很使用的方法,以后會(huì)經(jīng)常用到的。
- 事件循環(huán)綁定中
ctrlis[i].index = i這一行是重點(diǎn),它使你能夠順利找到你對(duì)誰(shuí)綁定事件。 - 運(yùn)動(dòng)封裝中我們首先要找到目標(biāo)點(diǎn),然后減去當(dāng)前l(fā)eft值再除以運(yùn)動(dòng)次數(shù)來(lái)算出運(yùn)動(dòng)距離。這個(gè)是運(yùn)動(dòng)起來(lái)的關(guān)鍵。
-
ctrlis[index%ctrlis.length].className="active"這一行代碼是最不要忽視的,它是動(dòng)態(tài)改變小圓點(diǎn)的樣式,因?yàn)槲覀冏隽藷o(wú)縫滾動(dòng),但是小圓點(diǎn)還是只有我們能看到的圖片的個(gè)數(shù),重復(fù)的不算,所以要進(jìn)行取余數(shù)判斷,才不會(huì)報(bào)錯(cuò)。
好了,大概就是這么多內(nèi)容,有什么不足之處還希望大家見(jiàn)諒。