摘要:前段時間學習了淘寶首頁的靜態頁面,其中收獲較大的的就是這個循環播放的圖片輪播組件,本文就將相關制作經驗分享給大家。作為演示,用標簽代替了圖片。關鍵使用不同背景色的替代圖片。
前段時間學習了淘寶首頁的靜態頁面,其中收獲較大的的就是這個循環播放的圖片輪播組件,本文就將相關制作經驗分享給大家。
先看看在線DEMO:原生JS循環播放圖片輪播組件?(支持IE8+,本文中的在線demo均未經過壓縮,可以直接在瀏覽器中調試)
以及GitHub倉庫地址及完整代碼:JuniorTour/simple-standard-js-carousel
一、思路講解: 1.先說基本的非循環無過渡圖片輪播:這個思路還是很簡單的,通過觀察一些圖片輪播就可以發現,圖片輪播一般是以一個尺寸較小的父元素作為窗口,包裹住一組較長的長條狀的項目(item)子元素,再利用?overflow: hidden; ,將父元素作為“窗口”,只顯示出的項目子元素的一部分,并通過改變項目子元素的定位或translate3d屬性,實現多張圖片項目動態播放。
基本原理可以參考這個demo:圖片輪播基本原理演示
2.比較有意思的其實是循環的功能:但是這樣簡單的輪播是不會循環播放的,也就是說當一輪圖片項目(item)播放到結尾;或者當在第一張圖(第一個項目)繼續向前時,就會超出內容子元素,出現空白部分,這一般不是我們想要的結果。
有多種思路可以實現循環播放,我觀察到淘寶網首頁的圖片輪播是這樣的思路:
復制開頭和結尾的項目,并分別放在開頭和結尾,當播放到開頭或結尾的項目,繼續播放,需要循環時,臨時取消transition屬性,并立即用定位跳轉至相應的真正的開頭或結尾之后,再恢復原來的transition,繼續正常滾動播放,從而利用視覺上的“欺騙”,實現帶有過渡效果的循環播放。
相應的原理可以參考這個demo:圖片輪播循環原理演示
二、HTML標記部分核心理念是簡潔、語義化。這部分因為我學過bootstrap框架所以借鑒了bootstrap的HTML標記結構。
整體結構為:
外層的.carousel-wrapper包裹著輪播的三個主要部分,分別是:
.carousel-item-wrapper:項目內容部分(作為演示,本文中的demo使用a標簽代替了圖片,大家可以自行嘗試替換為圖片;同時添加了文字序號標記,以便于觀察理解,尤其要注意兩個復制的開頭和結尾項目copy-1和copy-5)。
.carousel-control-wrapper:控制按鈕部分,即兩個用于控制左右移動的按鈕。
.carousel-index-wrapper:索引按鈕部分,即圖片輪播中的那一排“小圓點”。為了便于用JS操控,我添加了id作為“鉤子”。而bootstrap在這里用的是自定義的data屬性。
三、CSS樣式部分
總的來說比較簡單,重要的地方我加上了注釋,有存疑的地方,歡迎和我交流。
/*reset*/ * { border: none; padding: 0; margin: 0; } button { outline: none; } li { list-style: none; } .carousel-wrapper { width:520px; height:280px; overflow: hidden; /*關鍵*/ position: relative; margin: 100px auto; } .carousel-item-wrapper { width:3640px; height:280px; position: absolute; top: 0; left: -520px; transition: left .2s ease-in; } .carousel-item a { display: block; background-color: red; width:520px; height: 280px; } /*使用不同背景色的a替代圖片。*/ .carousel-item:nth-child(1) a { background-color: rgb(129,194,214); /*第五張圖片的復制*/ } .carousel-item:nth-child(2) a { background-color: rgb(129,146,214); } .carousel-item:nth-child(3) a { background-color: rgb(217,179,230); } .carousel-item:nth-child(4) a { background-color: rgb(220,247,161); } .carousel-item:nth-child(5) a { background-color: rgb(131,252,216); } .carousel-item:nth-child(6) a { background-color: rgb(129,194,214); } .carousel-item:nth-child(7) a { background-color: rgb(129,146,214); /*第一張圖片的復制*/ } .carousel-item { float: left; } .carousel-index-mark { font-size:60px; color: black; position: absolute; top: 0; } .carousel-control-wrapper { transition: all .2s; } .carousel-wrapper:hover button { display: block; } .carousel-control-wrapper button { transition: all .2s linear; display: none; width:24px; height:36px; line-height:36px; background-color: rgba(0,0,0,.3); color: #fff; position: absolute; top: 50%; cursor: pointer; } button#prev { left:0; } button#next { right:0; } button i { font-size: 18px; } .carousel-index-wrapper { width:65px; height:13px; overflow: hidden; position: absolute; bottom:15px; left:50%; margin-left: -33px; } .carousel-index-btn { width:9px; height:9px; float: left; margin:2px; background-color: #b7b7b7; border-radius: 50%; text-indent: -999em; /*這個-999em的文字對齊聲明有助于增強可訪問性。*/ cursor: pointer; } .active-carousel-index-btn { background-color: #f44103; }四、JS部分
這一塊是主要部分,內容較多,因此我們逐步來實現各部分功能以便于理解。
0.功能和結構分析:根據最開始的思路講解,我們把這個輪播的JavaScript功能大致分為以下4個部分:
1.左右滑動按鈕功能
2.索引按鈕跳轉功能
3.自動播放功能
4.循環播放功能。
我們來分別逐步實現。
1.實現左右滑動按鈕功能:function addLoadEvent(func) { var oldLoad = window.onload; if (typeof oldLoad != "function") { window.onload = func; } else { window.onload = function () { oldLoad(); func(); } } } //給文檔加載完成后的load事件綁定相應的處理函數: addLoadEvent(preventDefaultAnchors); addLoadEvent(carouselControl); /*用一個對象把輪播組件的相關參數封裝起來,優點是靈活便于擴展升級;缺點是同時也增加了文件的體積。*/ var carouselInfo = { itemWidth: 520, trueItemNum: 5, itemNum: 7, totalWidth: 7 * 520 }; //阻止a標簽默認的點擊跳轉行為 function preventDefaultAnchors() { var allAnchors = document.querySelectorAll("a"); for (var i = 0; i < allAnchors.length; i++) { allAnchors[i].addEventListener("click", function (e) { e.preventDefault(); }, false); } } function carouselControl () { var prev = document.querySelector("#prev"); var next = document.querySelector("#next"); var carouselWrapper = document.querySelector(".carousel-wrapper"); prev.onclick = function () { slide(-1); }; next.onclick = function () { slide(1); }; } function slide(slideItemNum) { var itemWrapper=document.querySelector(".carousel-item-wrapper"); var currentLeftOffset=(itemWrapper.style.left)?parseInt(itemWrapper.style.left): 0, targetLeftOffset=currentLeftOffset-(slideItemNum*carouselInfo.itemWidth); itemWrapper.style.left=targetLeftOffset+"px"; }
第1步的demo:carousel-step-1
2.實現索引按鈕跳轉功能:function carouselControl() { var prev = document.querySelector("#prev"); var next = document.querySelector("#next"); var carouselWrapper = document.querySelector(".carousel-wrapper"); //添加索引按鈕的引用 var indexBtns = document.querySelectorAll(".carousel-index-btn"); //標記當前所在的圖片編號,用于配合控制.index-btn。 var currentItemNum = 1; prev.onclick = function () { //把滑動功能和切換索引按鈕功能裝入一個函數之中,以便于獲取當前索引: currentItemNum=prevItem(currentItemNum); }; next.onclick = function () { //把滑動功能和切換索引按鈕功能裝入一個函數之中,以便于獲取當前索引: currentItemNum=nextItem(currentItemNum); }; for (var i = 0; i < indexBtns.length; i++) { //利用立即調用函數,解決閉包的副作用,傳入相應的index值 (function (i) { indexBtns[i].onclick = function () { slideTo(i+1); currentItemNum=i+1; } })(i); } } function nextItem(currentItemNum) { slide(1); currentItemNum += 1; if (currentItemNum == 6) currentItemNum = 1; switchIndexBtn(currentItemNum); return currentItemNum; } function prevItem(currentItemNum) { slide(-1); currentItemNum -= 1; if (currentItemNum == 0) currentItemNum = 5; switchIndexBtn(currentItemNum); return currentItemNum; } //添加直接跳轉函數: function slideTo(targetNum) { var itemWrapper=document.querySelector(".carousel-item-wrapper"); itemWrapper.style.left=-(targetNum*carouselInfo.itemWidth)+"px"; switchIndexBtn(targetNum); } function slide(slideItemNum) { var itemWrapper = document.querySelector(".carousel-item-wrapper"); var currentLeftOffset = (itemWrapper.style.left) ? parseInt(itemWrapper.style.left) : 0, targetLeftOffset = currentLeftOffset - (slideItemNum * carouselInfo.itemWidth); itemWrapper.style.left = targetLeftOffset + "px"; } function switchIndexBtn(targetNum) { //切換當前的索引按鈕 //刪除過去激活的.active-carousel-index-btn var activeBtn=document.querySelector(".active-carousel-index-btn"); activeBtn.className=activeBtn.className.replace(" active-carousel-index-btn",""); //添加新的激活索引按鈕 var targetBtn=document.querySelectorAll(".carousel-index-btn")[targetNum-1]; targetBtn.className+=" active-carousel-index-btn"; }
第2步的demo:carousel-step-2
3.實現自動播放功能:function carouselControl() { //省略前面重復的代碼...... for (var i = 0; i < indexBtns.length; i++) { //利用立即調用函數,解決閉包的副作用,傳入相應的index值 (function (i) { indexBtns[i].onclick = function () { slideTo(i+1); currentItemNum=i+1; } })(i); } //添加定時器 var scrollTimer; function play() { scrollTimer=setInterval(function () { currentItemNum=nextItem(currentItemNum); },2000); } play(); function stop() { clearInterval(scrollTimer); } //綁定事件 carouselWrapper.addEventListener("mouseover",stop); carouselWrapper.addEventListener("mouseout",play,false); /*DOM二級的addEventListener相對于on+sth的優點是: * 1.addEventListener可以先后添加多個事件,同時這些事件還不會相互覆蓋。 * 2.addEventListener可以控制事件觸發階段,通過第三個可選的useCapture參數選擇冒泡還是捕獲。 * 3.addEventListener對任何DOM元素都有效,而不僅僅是HTML元素。*/ }
第3步的demo:carousel-step-3
4.關鍵點:實現循環播放功能:function slide(slideItemNum) { var itemWrapper = document.querySelector(".carousel-item-wrapper"); var currentLeftOffset = (itemWrapper.style.left) ? parseInt(itemWrapper.style.left) : 0, targetLeftOffset = currentLeftOffset - (slideItemNum * carouselInfo.itemWidth); /*不在這里跳轉了。先處理偏移值,實現循環,再跳轉。*/ //itemWrapper.style.left = targetLeftOffset + "px"; switch (true) { /*switch 的語法是:當case之中的表達式等于switch (val)的val時,執行后面的statement(語句)。*/ case (targetLeftOffset>0): itemWrapper.style.transition="none"; itemWrapper.style.left=-carouselInfo.trueItemNum*carouselInfo.itemWidth+"px"; /*此處即相當于:itemWrapper.style.left="-2600px";*/ targetLeftOffset=-(carouselInfo.trueItemNum-1)*carouselInfo.itemWidth; //相當于:targetLeftOffset=-2080; break; case (targetLeftOffset<-(carouselInfo.totalWidth-carouselInfo.itemWidth)): //此處即相當于:targetLeftOffset<-3120 itemWrapper.style.transition="none"; itemWrapper.style.left=-carouselInfo.itemWidth+"px"; //相當于:itemWrapper.style.left="-520px"; targetLeftOffset=-carouselInfo.itemWidth*2; //相當于:targetLeftOffset=-1040; break; } /*這里我使用了setTimeout(fn,0)的hack * 參考bootstrap的carousel.js源碼,似乎也利用了setTimeout(fn,0)這一hack。 * * stackoverflow上有對這一hack的討論和解釋: * http://stackoverflow.com/questions/779379/why-is-settimeoutfn-0-sometimes-useful * 根據第二個回答,我個人的理解是:setTimeout(fn,0)相當于異步執行內部的代碼fn, * 具體到這個輪播,就是在上一輪非過渡定位的頁面渲染工作(switch語句內部的case)結束之后,再執行setTimeout內部的過渡位移工作。 * 從而避免了,非過渡的定位還未結束,就恢復了過渡屬性,使得這一次非過渡的定位也帶有過渡效果。 **/ //各位可以試一試,把setTimeout內部的代碼放在外部,“循環”時會有什么樣的錯誤效果。 //itemWrapper.style.transition="left .2s ease-in"; //itemWrapper.style.left=targetLeftOffset+"px"; setTimeout(function () { itemWrapper.style.transition="left .2s ease-in"; itemWrapper.style.left=targetLeftOffset+"px"; },20); }
第4步的demo:carousel-step-4
至此,就完成了一個完整的循環播放圖片輪播,欣賞一下自己的杰作吧~~~ヾ(??▽?)ノ
五、源碼及示例: 1.GitHub倉庫地址及完整代碼:JuniorTour/simple-standard-js-carousel 2.在線demo:原生JS循環播放圖片輪播組件?很慚愧,只做了一點簡單的工作。如果覺得本文不錯的話,歡迎給我的GitHub點贊!
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/83417.html
摘要:前段時間學習了淘寶首頁的靜態頁面,其中收獲較大的的就是這個循環播放的圖片輪播組件,本文就將相關制作經驗分享給大家。作為演示,用標簽代替了圖片。關鍵使用不同背景色的替代圖片。 前段時間學習了淘寶首頁的靜態頁面,其中收獲較大的的就是這個循環播放的圖片輪播組件,本文就將相關制作經驗分享給大家。 先看看在線DEMO:原生JS循環播放圖片輪播組件?(支持IE8+,本文中的在線demo均未經過壓縮...
摘要:前段時間學習了淘寶首頁的靜態頁面,其中收獲較大的的就是這個循環播放的圖片輪播組件,本文就將相關制作經驗分享給大家。作為演示,用標簽代替了圖片。關鍵使用不同背景色的替代圖片。 前段時間學習了淘寶首頁的靜態頁面,其中收獲較大的的就是這個循環播放的圖片輪播組件,本文就將相關制作經驗分享給大家。 先看看在線DEMO:原生JS循環播放圖片輪播組件?(支持IE8+,本文中的在線demo均未經過壓縮...
摘要:綁定輪播事件然后是鼠標移入移出事件的綁定鼠標移入移出事件移入時停止輪播播放的定時器,移出后自動開始下一張的播放。 通過上一篇文章的學習,我們基本掌握了一個輪子的封裝和開發流程。那么這次將帶大家開發一個更有難度的項目——輪播圖,希望能進一步加深大家對于面向對象插件開發的理解和認識。 So, Lets begin! 目前項目使用 ES5及UMD 規范封裝,所以在前端暫時只支持標簽的引入方式...
摘要:鼠標放到輪播圖的圖片上時不再自動輪播并且左右箭頭顯示出來,鼠標移開時左右箭頭隱藏掉并且自動輪播。核心原理清除定時器,綁定事件,重構下代碼封裝出往右往左輪播函數和自動輪播函數。 需求與分析 需求:循環無縫自動輪播五張圖,按左右箭頭可以手動切換圖片,鼠標點擊輪播圖下面按鈕 1 2 3 4 5會跳轉到對應的第1 2 3 4 5張圖片。鼠標放到輪播圖的圖片上時不再自動輪播并且左右箭頭顯示出來,...
閱讀 1804·2023-04-26 02:32
閱讀 567·2021-11-18 13:12
閱讀 2446·2021-10-20 13:48
閱讀 2515·2021-10-14 09:43
閱讀 3825·2021-10-11 10:58
閱讀 3483·2021-09-30 10:00
閱讀 2932·2019-08-30 15:53
閱讀 3487·2019-08-30 15:53