案例——輪播圖(原生JS實現)
阿新 • • 發佈:2021-02-17
技術標籤:JavaScriptjavascript
效果圖
首先我們來理一下思路
-
搭建結構
注意點:
我們需要一個container輪播圖容器,溢位隱藏
我們需要一個wrapper容器用於存放所有的圖片,wrapper相對於container定位,後期改變wrapper的left值實現輪播圖的切換 -
寫樣式…
-
寫js
- 獲取所有需要操作的元素
- 獲取資料(基於AJAX非同步獲取資料,當然沒有伺服器提供資料,只能自己寫一點)
- 實現資料繫結HTML頁面(基於Promise管理非同步操作)
注意繫結的時候圖片要多繫結一個,便於後面實現無縫輪播- (每隔interval秒,實現單張輪播圖的自動運動和切換)
- 實現輪播圖的自動運動和切換
- 設定輪播圖運動的基礎引數(全域性變數)stepIndex,autoTimer,interval
- 開啟定時器驅動自動輪播(實現每隔interval秒輪播圖的自動運動和切換)
- stepIndex++(圖片要切換了,當前圖片索引改變)
- 當索引大於原來的長度,讓其立即運動到第一張,再讓其運動第二張(最後一張圖片和第一張圖片一摸一樣,立即運動表示直接設定它的left屬性,讓它在運動最後一張圖片的時候切換到第一張圖片,人眼是看不出來的跳轉的,這樣可以實現無縫銜接)
- 設定動畫(讓圖片在1秒內完成切換)
- 切換焦點- 實現滑鼠進入和離開自動輪播的停止和開啟,和按鈕的隱藏和顯示
- 實現點選焦點時圖片的切換
- 實現點選按鈕時圖片的切換
然後直接上程式碼!!!
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>輪播圖</title>
<link rel="stylesheet/less" href="css/banner.less">
<script src="js/less.min.js"></script>
</head>
<body>
<section class="container" id="container">
<div class="wrapper">
<!-- <div><img src="img/1.png" alt=""></div>
<div><img src="img/2.png" alt=""></div>
<div><img src="img/3.png" alt=""></div>
<div><img src="img/4.png" alt=""></div> -->
</div>
<ul class="focus">
<!-- <li class="active"></li>
<li></li>
<li></li>
<li></li> -->
</ul>
<a href="javascropt:;" class="arrow arrowLeft"></a>
<a href="javascropt:;" class="arrow arrowRight"></a>
</section>
<script src="js/utils.js"></script>
<script src="js/animate.js"></script>
<script src="js/banner.js"></script>
</body>
</html>
css
@import "baseCss";
.container{
position: relative;
margin: 20px auto;
width: 1000px;
height: 300px;
overflow: hidden;
.wrapper{
position: absolute;
left: 0;
top: 0;
width: 4000px;
height: 100%;
div{
float: left;
width: 1000px;
height: 100%;
img{
width: 100%;
height: 100%;
}
}
}
.focus{
position: absolute;
left: 50%;
bottom: 10px;
transform: translateX(-50%);
height: 12px;
border-radius: 6px;
background: rgba(0, 0, 0, .5);
li{
float: left;
margin: 3px;
width: 6px;
height: 6px;
background: #fff;
border-radius: 50%;
&.active{
background: lightseagreen;
}
}
}
.arrow{
position: absolute;
display: none;
width: 41px;
height: 69px;
&.arrowLeft{
left: 0;
top: 50%;
transform: translateY(-50%);
background: url(../img/icon-slides.png) no-repeat -84px 0;
&:hover{
background: url(../img/icon-slides.png) no-repeat 0 0;
}
}
&.arrowRight{
right: 0;
top: 50%;
transform: translateY(-50%);
background: url(../img/icon-slides.png) no-repeat -126px 0;
&:hover{
background: url(../img/icon-slides.png) no-repeat -42px 0;
}
}
}
}
js
let bannerRender = (function() {
//1. 獲取操作的的元素
let container = document.querySelector('#container'),
wrapper = container.querySelector('.wrapper'),
focus = container.querySelector('.focus'),
arrowLeft = container.querySelector('.arrowLeft'),
arrowRight = container.querySelector('.arrowRight'),
slideList = null,
focusList = null;
//輪播圖運動的基礎引數
let stepIndex = 0, //記錄當前展示快的索引
autoTimer = null, //自動輪播的定時器
interval = 3000; //間隔多長時間自動切換
//2. 獲取資料
let queryData = function() {
return new Promise((resolve, reject) => {
let xhr = new XMLHttpRequest();
xhr.open('get', 'json/banner.json', true); //非同步獲取資料
xhr.onreadystatechange = () => {
if (xhr.readyState === 4 && xhr.status === 200) {
let data = JSON.parse(xhr.responseText);
resolve(data);
}
};
xhr.send(null);
});
};
//3. 實現資料繫結(獲取資料成功之後執行資料繫結方法)
let bindHTML = function(res) {
let strSlide = ``,
strFocus = ``;
res.forEach((item, index) => {
let {
id,
img = 'img/1.png',
desc = 'xiaomi',
link
} = item;
strSlide += `<div><img src="${img}" alt="${desc}"></div>`;
//ES6模板字串${}存放的是JS表示式,但是表示式要有返回值,因為我們要把返回值拼接到模板字串中
strFocus += `<li class="${index === 0?'active':''}"></li>`
});
//克隆一份到末尾
strSlide += `<div><img src="${res[0].img}" alt="${res[0].desc}"></div>`;
wrapper.innerHTML += strSlide;
focus.innerHTML += strFocus;
slideList = wrapper.querySelectorAll('.wrapper > div');
focusList = focus.querySelectorAll('.focus > li');
//根據slide的個數動態計算wrapper的寬度
utils.setCss(wrapper, 'width', slideList.length * 1000);
};
//改變焦點
let changeFocus = function() {
let tempIndex = stepIndex; //建立臨時索引
tempIndex === slideList.length - 1 ? tempIndex = 0 : null;
[].forEach.call(focusList, (item, index) => {
item.className = index === tempIndex ? 'active' : '';
});
};
//4. 實現輪播圖的運動和切換
//輪播圖無縫銜接原理:
//- 克隆第一張到末尾(在資料繫結的時候克隆)
//- 正常累加運動,當運動到末尾(此時的末尾是克隆的哪一張),再過3秒切換的時候,後面就沒有圖片了,此時我們讓其立即切換到真實第一張的位置
// (立即切換,沒有動畫,left=0,剛才展示的最後一張和真實的第一張長的一樣,給使用者感覺沒有切換),緊接著運動到第二張即可
let autoMove = function() {
stepIndex++;
//如果索引大於原來的長度,讓其瞬間運動到第一張,再讓其運動到第二張
if (stepIndex > (slideList.length - 1)) {
utils.setCss(wrapper, 'left', 0);
stepIndex = 1; //不是等於0,而是等於1,這樣可以切換到第二張
}
//基於自己封裝的animate實現動畫
animate(wrapper, {
left: -stepIndex * 1000
}, 1000);
//每一次運動完成,需要讓焦點跟著切換
changeFocus();
};
//5. 實現滑鼠進入和離開控制自動輪播的停止和開啟
let handleContainer = function() {
container.onmouseenter = function() {
clearInterval(autoTimer);
arrowLeft.style.display = arrowRight.style.display = 'block';
};
container.onmouseleave = function() {
autoTimer = setInterval(autoMove, interval);
arrowLeft.style.display = arrowRight.style.display = 'none';
};
};
//6. 實現點選焦點圖片切換
let handleFocus = function() {
[].forEach.call(focusList, (item, index) => {
item.onclick = function() {
stepIndex = index;
animate(wrapper, {
left: -stepIndex * 1000
}, 1000);
changeFocus();
};
});
};
//7. 實現點選按鈕圖片
let handleArrow = function() {
arrowRight.onclick = autoMove;
arrowLeft.onclick = function() {
stepIndex--;
//如果索引小於零,則是第一張,不能再向右運動了,此時因當瞬間運動到最後一張(和第一張一模一樣),再讓其運動到倒數第二張
if (stepIndex < 0) {
utils.setCss(wrapper, 'left', -(slideList.length - 1) * 1000);
stepIndex = slideList.length - 2;
}
animate(wrapper, {
left: -stepIndex * 1000
}, 1000);
changeFocus();
};
}
return {
init: function() {
let promise = queryData();
promise.then(res => {
bindHTML(res);
}).then(() => {
//開啟定時器驅動的自動輪播
autoTimer = setInterval(autoMove, interval);
}).then(() => {
//左右按鈕或者焦點切換
handleContainer();
handleFocus();
handleArrow();
});
}
};
})();
bannerRender.init();