什么是輪播圖?
輪播圖辰妙,圖片旋轉(zhuǎn)器,滑片甫窟,無論你怎么叫這玩意密浑,它在網(wǎng)絡(luò)上無處不在。輪播圖在電商網(wǎng)站主頁(yè)上廣泛應(yīng)用粗井,大多數(shù)電商網(wǎng)站的主頁(yè)上都有它:
本輪播圖Demo
喏~兩個(gè)鏈接甩給泥萌
Github倉(cāng)庫(kù)文件
在線Demo(移動(dòng)端加載很慢)
前言
網(wǎng)上有很多的輪播圖特效,部分采用的transition屬性結(jié)合JS實(shí)現(xiàn)滾動(dòng)浇衬,但是很遺憾沒有無縫效果懒构,什么是無縫?我給前端小白畫了一個(gè)示意圖耘擂。另外本文是我寫的第一篇文章胆剧,難免有生疏之處。包含很多知識(shí)點(diǎn)回顧醉冤,很適合JS新手學(xué)習(xí)秩霍。
當(dāng)焦點(diǎn)位于圖片1時(shí)蚁阳,如果再往前滾的話铃绒,整個(gè)隊(duì)列會(huì)被拉倒真正的第五張圖。至于真正的圖片1前面的副本圖片5只是讓用戶產(chǎn)生視覺差螺捐,從而不會(huì)讓用戶明顯感覺到圖片被倒向了圖片5匿垄,看起來就像時(shí)無縫輪播。
同理當(dāng)焦點(diǎn)位于圖片5時(shí)归粉,如果再往后滾椿疗,道理同上不再贅述。
實(shí)現(xiàn)功能
1.當(dāng)鼠標(biāo)放入容器內(nèi)時(shí)左右出現(xiàn)控制按鈕糠悼,并且輪播動(dòng)畫停止届榄。
2.當(dāng)鼠標(biāo)移出時(shí),控制按鈕隱藏倔喂,輪播繼續(xù)铝条。
3.焦點(diǎn)隨圖片的滾動(dòng)而變化。
4.跳躍點(diǎn)擊焦點(diǎn)席噩,會(huì)跳轉(zhuǎn)到相應(yīng)的圖片班缰。
5.以及前沿所述的無縫輪播。
開搞~~
Html代碼:
(內(nèi)有注釋解析)
<div id="container">
<div id="list" style="left: -600px;">//初始狀態(tài)是真正的圖片1悼枢,也就是絕對(duì)定位-600px
![](img/555.jpg)
![](img/111.jpg)
![](img/222.jpg)
![](img/333.jpg)
![](img/444.jpg)
![](img/555.jpg)
![](img/111.jpg)
</div>
<div id="buttons">
<span index="1" class="on"></span>//動(dòng)畫開始時(shí)小圓點(diǎn)位于第一個(gè)
<span index="2"></span>
<span index="3"></span>
<span index="4"></span>
<span index="5"></span>
</div>
<a id="prev" class="arrow"><</a>//前一個(gè)箭頭
<a id="next" class="arrow">></a>//后一個(gè)箭頭
</div>
開始講解代碼:
1.箭頭控制
var prev=document.getElementById("prev");
var next=document.getElementById("next");
var list=document.getElementById("list");
prev.onclick=function(){
list.style.left=parseInt(list.style.left)-600+"px";
}
next.onclick=function(){
list.style.left=parseInt(list.style.left)+600+"px";
}
給a標(biāo)簽綁定點(diǎn)擊事件埠忘,先獲取list
的left
屬性并且取出數(shù)字進(jìn)行運(yùn)算操作。下面我們來做一些優(yōu)化,把定義一個(gè)function animate()
函數(shù)莹妒,傳入offset
參數(shù)名船,并把var newLeft=parseInt(list.style.left) +offset;
,然后讓prev
和next
的點(diǎn)擊事件調(diào)用這個(gè)函數(shù)旨怠。
function animate(offset){
list.style.left=newLeft+offset+"px";
}
prev.onclick=function(){
animate(-600);
}
next.onclick=function(){
animate(600);
}
然后我們會(huì)發(fā)現(xiàn)當(dāng)我們點(diǎn)擊到第五張圖片left=-3000px
時(shí)渠驼,它應(yīng)該滾到真正的第1張而不是副本1。我們可以像下面這樣寫實(shí)現(xiàn)無縫滾動(dòng):
function animate(offset){
list.style.left=newLeft+offset+"px";
if (newLeft >-600) {
list.style.left=-3000+"px";
};
if (newLeft <-3000) {
list.style.left=-600+"px";
};
}
用箭頭控制圖片的輪播大工告成<濉C陨取(撒花~)
2.焦點(diǎn)跟隨
這個(gè)功能可能比較難以理解,其實(shí)和第一部分是一樣的爽哎。首先考慮到prev和next點(diǎn)擊事件中要有標(biāo)記蜓席,這個(gè)標(biāo)記就是一個(gè)掛鉤,再定義一個(gè)函數(shù)利用這個(gè)掛鉤來跟隨焦點(diǎn)倦青。我們用showButton()
函數(shù),全局定義變量var index=1
先讓第一幅圖的焦點(diǎn)亮起來。下面我們來看代碼(忽略animate
變量盹舞,下一部分我們會(huì)講到):
var buttons=document.getElementById("buttons").getElementsByTagName("span");
var index=1//buttons[0].classNme="on";
var animated=false;//全局動(dòng)畫停止標(biāo)記
function shownButton(){
/* for循環(huán)的作用就是當(dāng)prev和next每click一次产镐,
就會(huì)清除一次前一個(gè)class為on的span元素*/
for (var i = 0; i < buttons.length ; i++) {
buttons[i].className="";
}
buttons[index -1].className="on";//焦點(diǎn)跟隨
}
prev.onclick=function(){
if (!animated) {//這里判斷
if (index==1) {
/*這就是我們下面要講到的當(dāng)焦點(diǎn)位于第一個(gè)span時(shí)踢步,讓它跳轉(zhuǎn)到第5個(gè)*/
index=5;
}else {
index -=1;
}
shownButton();//把上一個(gè)亮起的滅掉癣亚,下一個(gè)亮起
animate(600);
}
};
next.onclick=function(){
if (!animated) {/*全局變量animated=false,那么获印!animated=true
if (index==5) {
index=1;
}else {
index +=1;
}
shownButton();
animate(-600);
}
};
3.焦點(diǎn)輪播(實(shí)現(xiàn)功能第四點(diǎn))
當(dāng)圖片位于第一個(gè)焦點(diǎn)時(shí)述雾,我點(diǎn)擊第四的焦點(diǎn)。left=-600px
變成了left=-2400px
話不多說兼丰,來看下面的代碼吧玻孟。
for (var i = 0; i < buttons.length; i++) {
buttons[i].onclick=function(){
//無關(guān)緊要,性能優(yōu)化使用鳍征,目的是當(dāng)index和myindex相等時(shí)黍翎,退出函數(shù)
if (this.className=="on") {
return;
}
var myIndex=parseInt(this.getAttribute("index"));//index不是a的固有屬性,因此要用dom調(diào)用
var offset=-600*(myIndex-index);
if (!animated) {/*又出現(xiàn)了這個(gè)animated艳丛,
在此意思是如果animate()執(zhí)行過程中匣掸,animated=true,那么animate()不能再次被 調(diào)用*/
animate(offset);
}
index=myIndex;//更新index氮双,便于下一次的輪播
shownButton();
}
}
4.動(dòng)畫函數(shù)
動(dòng)畫函數(shù)go()
整合到了animate()
函數(shù)里了碰酝。只可意會(huì)不可言傳(手動(dòng)滑稽)直接上代碼吧:
function animate(offset){
var speed = offset/30;//每次的位移,分母越大越流暢
animated=true;//動(dòng)畫正在運(yùn)行戴差,別的事件不要來打擾
var newLeft=parseInt(list.style.left) +offset;
function go(){
if ( (speed > 0 && parseInt(list.style.left) < newLeft) || (speed < 0 && parseInt(list.style.left) > newLeft)) {
list.style.left = parseInt(list.style.left) + speed + 'px';
setTimeout(go, inteval);//遞歸函數(shù)
}
else
{
animated=false;
list.style.left=newLeft+"px";
if (newLeft >-600) {
list.style.left=-3000+"px";
};
if (newLeft <-3000) {
list.style.left=-600+"px";
};
}
}
go();
};
5.定時(shí)器
var container=document.getElementById("container");
var timer;
function play(){
timer=setInterval(function(){
next.onclick();
},2000);
}
function stop(){
clearInterval(timer);
}
play();
container.onmouseover=stop;
container.onmouseout=play;
最后放一遍總的JS代碼
高大上的JS代碼(滑稽)
< script >
window.onload = function ()
{
var prev = document.getElementById("prev");
var next = document.getElementById("next");
var list = document.getElementById("list");
var buttons = document.getElementById("buttons").getElementsByTagName("span");
var container = document.getElementById("container");
var index = 1;
var timer;
var animated = false;
function shownButton()
{
for (var i = 0; i < buttons.length ; i++)
{
if ( buttons[i].className == 'on')
{
buttons[i].className = '';
/* prev和next每click一次送爸,
就會(huì)清除一次前一個(gè)class為on的span元素,
所以沒有必要再去循環(huán)下面的span*/
break;
}
// 或者直接遍歷清除 buttons[i].className="";
}
buttons[index - 1].className = "on";
}
function animate(offset)
{
var time = 300;
var inteval = 10;
var speed = offset / (time / inteval);
animated = true;//更改全局變量碱璃,防止跳圖
var newLeft = parseInt(list.style.left) + offset;
function go()
{
if ( (speed > 0 && parseInt(list.style.left) < newLeft) || (speed < 0 && parseInt(list.style.left) > newLeft)) {
list.style.left = parseInt(list.style.left) + speed + 'px';
setTimeout(go, inteval);
}
else
{
animated = false;//全局變量
list.style.left=newLeft+"px";
if (newLeft > -600) {
list.style.left =- 3000 + "px";
};
if (newLeft <- 3000) {
list.style.left =- 600 + "px";
};
}
}
go();
};
prev.onclick = function ()
{
/*添加一個(gè)if判斷index為1時(shí)弄痹,如果繼續(xù)往前滾的話就讓index返回第五個(gè)span
但是當(dāng)快速點(diǎn)擊arrow時(shí)會(huì)出現(xiàn)一種span點(diǎn)亮延遲的情況∏镀鳎可以嘗試把判斷index是否大于1或小于5的情況放進(jìn)
判斷是否animated的if語(yǔ)句中肛真,先判斷能不能點(diǎn)擊,再點(diǎn)亮爽航。
*/
if (!animated) {
if (index == 1) {
index = 5;
}
else {
index -= 1;
}
shownButton();
animate(600);
}
};
next.onclick = function ()
{
if (!animated) {
if (index == 5) {
index = 1;
}
else {
index += 1;
}
shownButton();
animate(-600);
}
};
for (var i = 0; i < buttons.length; i++)
{
buttons[i].onclick = function ()
{
//無關(guān)緊要
if (this.className == "on") {
return;
}
var myIndex = parseInt(this.getAttribute("index"));
var offset =- 600 * (myIndex - index);
if (!animated) {
animate(offset);
}
index = myIndex;
shownButton();
}
}
function play()
{
timer = setInterval(function ()
{
next.onclick();
}, 2000);
}
function stop()
{
clearInterval(timer);
}
play();
container.onmouseover = stop;
container.onmouseout = play;
}
</script>
總結(jié)
其實(shí)寫這種技術(shù)性文章最能考驗(yàn)?zāi)闶欠窭斫饬诉@個(gè)特效蚓让,同時(shí)也是最累的。昨天晚上我在跟著慕課網(wǎng)做的時(shí)候讥珍,有一瞬間想放棄了历极,畢竟現(xiàn)在框架那么多,何必那么絞盡腦汁用一個(gè)復(fù)雜的函數(shù)做動(dòng)畫呢衷佃,直接引用JS庫(kù)多省事趟卸。但是直到我寫完這篇教程,我很慶幸我堅(jiān)持下來了氏义。這是我的第一篇文章锄列,簡(jiǎn)書提供了一個(gè)很棒的平臺(tái)來記錄一個(gè)平凡人的世界。以后會(huì)常來這里惯悠,分享自己的所得邻邮,這也是一種喜悅。