原生JS實現"旋轉木馬"效果的圖片輪播插件

来源:http://www.cnblogs.com/LuckyWinty/archive/2016/04/24/5427842.html
-Advertisement-
Play Games

一、寫在最前面 最近都忙一些雜七雜八的事情,複習軟考、研讀經典...好像都好久沒寫過博客了。。。 我自己寫過三個圖片輪播,一個是簡單的原生JS實現的,沒有什麼動畫效果的,一個是結合JQuery實現的,淡入淡出切換的。現在想做一個酷一點的放在博客或者個人網站,到時候可以展示自己的作品。逛了一下慕課網, ...


一、寫在最前面

最近都忙一些雜七雜八的事情,複習軟考、研讀經典...好像都好久沒寫過博客了。。。

我自己寫過三個圖片輪播,一個是簡單的原生JS實現的,沒有什麼動畫效果的,一個是結合JQuery實現的,淡入淡出切換的。現在想做一個酷一點的放在博客或者個人網站,到時候可以展示自己的作品。逛了一下慕課網,發現有個旋轉木馬的jquery插件課程,有點酷酷的,於是就想著用原生JS封裝出來。做起來才發現,沒有自己想象中的那麼容易。。。不啰嗦了,講解一下實現過程吧。

二、效果

由於自己的伺服器還沒弄好。線上演示不了(ORZ...)。。。只能放一張效果圖了。。。

 

從圖片上還是可以看出大概效果的,我就不多說了。想看真實代碼效果的,歡迎到我的github上面download代碼,別忘了給我的github項目點個星星噢^_^

三、實現過程

 html結構

 

<div class="carrousel-main" data-setting='{"width":1000,"height":400,
	"carrouselWidth":750,
   	"carrouselHeight":400,
   	"scale":0.9,
   	"verticalAlign":"middle"}'>
		<div class="carrousel-btn carrousel-btn-pre"></div>
		<ul class="carrousel-list">
			<li class="carrousel-item">
				<a href="#"><img src="img/1.jpg"></a>
			</li>
			<li class="carrousel-item">
				<a href="#"><img src="img/2.jpg"></a>
			</li>
			<li class="carrousel-item">
				<a href="#"><img src="img/3.jpg"></a>
			</li>
			<li class="carrousel-item">
				<a href="#"><img src="img/4.jpg"></a>
			</li>
			<li class="carrousel-item">
				<a href="#"><img src="img/5.jpg"></a>
		</ul>
		<div class="carrousel-btn carrousel-btn-next"></div>
	</div>

 

這個結構和一般輪播的html代碼結構是一樣的,稍有不同就是,主輪播div上面有一個data-setting的屬性,這個屬性裡面就是一些輪播效果的參數。參數的具體意義稍後再講解。

css部分的代碼就不貼了,最重要就是要註意元素的絕對定位,由效果圖可以看出來,每張圖片的位置、大小都不一樣,所以這些都是通過js控制的,因此需要絕對定位。下麵重點講一下js實現過程。

JS實現過程

下麵講幾個JS的關鍵步驟,做好了這幾個步驟之後,應該就沒有什麼難點了。

①預設參數

既然是封裝插件,那麼肯定會有一些參數的預設值需要配置的啦。這個插件中,主要有如下參數:

 

	width:1000,  //幻燈片區域的寬度
   	height:400,  //幻燈片區域的高度
   	carrouselWidth:700, //幻燈片第一幀的寬度
   	carrouselHeight:400, //幻燈片第一幀的高度
   	scale:0.9,//記錄顯示比例關係,例如第二張圖比第一張圖顯示的時候寬高小多少
   	autoPlay:true,//是否自動播放
   	timeSpan:3000,//自動播放時間間隔
   	verticalAlign:'middle'  //圖片對齊方式,有top\middle\bottom三種方式,預設為middle

 

②封裝對象

因為一個網站可能有多個地方都會用到同一個輪播插件,所以封裝很關鍵。定義了這個對象之後,如果給對象定義一個初始化方法是可以創建多個對象的,只需要把所有類相同的dom傳進去就可以了。所以,我的初始化方法如下:

Carousel.init=function(carrousels){
	var _this=this;
       //將nodeList轉換為數組
       var cals= toArray(carrousels); 
/*因為原生JS獲取所有的類,得到的是一個nodeList,是一個類數組,如果想要使用數組的方法則需要轉化為真正的數組。這裡toArray為轉化方法。*/ cals.forEach(function(item,index,array){ new _this(item); }); }

這樣的話,我在window.onload的時候,調用Carrousel.init(document.querySelectorAll('.carrousel-main'));這樣就可以創建多個輪播啦!

③初始化好第一幀的位置參數

因為,第一幀之後的所有幀的相關參數都是參照第一幀來定義的,因此,定義好第一幀很關鍵。

	setValue:function(){
	this.carrousel.style.width=this.Settings.width+'px';
	this.carrousel.style.height=this.Settings.height+'px';
        /*左右按鈕設置,這裡要讓左右按鈕平均地瓜分輪播區域寬減去第一幀寬度之後的區域,z-index要比除第一幀外所有圖片都高,而圖片剛好左右分放置,因此z-index的值就是圖片數量的一半。*/
        var btnW=(this.Settings.width-this.Settings.carrouselWidth)/2;
        this.preBtn.style.width=btnW+'px';
        this.preBtn.style.height=this.Settings.height+'px';
        this.preBtn.style.zIndex=Math.ceil(this.carrouselItems.length/2);

        this.nextBtn.style.width=btnW+'px';
        this.nextBtn.style.height=this.Settings.height+'px';
        this.nextBtn.style.zIndex=Math.ceil(this.carrouselItems.length/2);
        //第一幀相關設置
        this.carrouselFir.style.left=btnW+'px';
        this.carrouselFir.style.top=this.setCarrouselAlign(this.Settings.carrouselHeight)+'px';
        this.carrouselFir.style.width=this.Settings.carrouselWidth+'px';
        this.carrouselFir.style.height=this.Settings.carrouselHeight+'px';
        this.carrouselFir.style.zIndex=Math.floor(this.carrouselItems.length/2);
    },

這裡,就是new對象的時候,就到dom結點中獲取data-setting參數,然後更新預設參數配置。這裡有個地方需要註意的,獲取dom的參數不能直接以賦值的方式更新預設參數,因為用戶配置參數的時候,不一定會所有參數都配置一次。如果直接賦值而用戶剛好不是所有參數都配置的話就會造成參數丟失。這裡我是自己寫了一個類似JQuery中的$.extend方法的對象擴展方法來更新參數的。具體就不列舉了,感興趣的可以去下載

 ④其他圖片位置設置

 這裡的圖片實際上就是把除第一張之外的圖片,平均地分到左右兩則,而左邊的圖片位置和右邊的是不同的,因此需要分別配置:

        //設置右邊圖片的位置關係
        var rightIndex=level;
        rightSlice.forEach(function(item,index,array){
        	rightIndex--;
        	var i=index;
        	rw=rw*carrouselSelf.Settings.scale;//右邊的圖片是按照scale比例逐漸變小的
        	rh=rh*carrouselSelf.Settings.scale;

        	item.style.zIndex=rightIndex;//越往右邊z-index的值越小,可以用圖片數量的一般逐漸遞減
        	item.style.width=rw+'px';
        	item.style.height=rh+'px';
        	item.style.opacity=1/(++i);//越往右邊透明度越小
//這裡的gap計算方法為:輪播區域減去第一幀寬度,除2,再除左邊或者右邊的圖片張數 item.style.left=(constOffset+(++index)*gap-rw)+'px';//left的值實際上就是第一幀的left+第一幀的寬度+item的間距減去item的寬度 item.style.top=carrouselSelf.setCarrouselAlign(rh)+'px'; });

左邊的設置方法類似且更為簡單,就不細說了。

⑤旋轉時所有圖片的位置大小調整

這一步很關鍵,點擊右邊按鈕下一張的即為左旋轉,而點擊左邊按鈕上一張即為右旋轉。此時,我們只需要把所有的圖片看成一個環形那樣,點擊一次,換一次位置即完成旋轉。具體為左旋轉的時候,令第二張的參數等於第一張,第三張等於第二張...而最後一張等於第一張即可。右旋轉的時候,令第一張的參數等於第二張,第二張的參數等於第三張...而最後一張的參數等於第一張即可。

這裡就說說左旋轉吧

                  if(dir=='left'){
   			toArray(this.carrouselItems).forEach(function(item,index,array){
   				var pre;
   				if(index==0){//判斷是否為第一張
   					pre=_this.carrouselLat;//讓第一張的pre等於最後一張
   					var width=pre.offsetWidth; //獲取相應參數
   					var height=pre.offsetHeight;
   					var zIndex=pre.style.zIndex;
   					var opa=pre.style.opacity;
   					var top=pre.style.top;
   					var left=pre.style.left;
   				}else{
   					var width = tempWidth;
   					var height = tempHeight;
   					var zIndex = tempZIndex;
   					var opa = tempOpacity;
   					var top = tempTop;
   					var left = tempLeft;
   				}
                       //這裡需要註意,因為第二張圖片是參照第一張的,而這樣改變的時候,第一張是首先被改變的,因此必須先把第一張的相關參數臨時保存起來。
   				tempWidth = item.offsetWidth;
   				tempHeight = item.offsetHeight;
   				tempZIndex = item.style.zIndex;
   				tempOpacity = item.style.opacity;
   				tempTop = item.style.top;
   				tempLeft = item.style.left;

   				item.style.width=width+'px';
   				item.style.height=height+'px';
   				item.style.zIndex=zIndex;
   				item.style.opacity=opa;
   				item.style.top=top;
   					// item.style.left=left;
   					animate(item,'left',left,function(){//自定義的原生js動畫函數
   						_this.rotateFlag=true;
   					});
   				});
   		}

這裡的旋轉,如果不使用一些動畫過度,會顯得很生硬。但是原生JS並沒有動畫函數,這裡我是自己寫了一個模仿的動畫函數。其原理就是獲取dom原來的樣式值,與新傳入的值比較。用一些方法定義一個速度。我這裡的速度就是用其差值除18.然定義一個計時器,參考了一下jquery源碼裡面的時間間隔為每13毫秒執行一次。然後才原來的樣式值每次加上speed後等於傳入的值的時候清楚計時器即可。具體可以看這裡

好啦,關鍵的地方都差不多啦,如果明白這些過程應該就很容易了!

四、總結思考

總結:

個人感覺這還是一個比較好理解的插件。如果能結合JQuery來做就相當簡單了。但是用原生來寫的話,還是有一些不那麼流暢的感覺。應該是自定義動畫比不上JQuery封裝好的動畫吧。

還有,這個插件因為圖片需要平均分到左右兩邊,於是對於偶數數量的圖片來說,這裡用的方法是克隆第一張,然後加到最後,形成一個奇數。

思考:

如果說有bug的話,那就是我定義了一個rotateFlag的標誌去判斷當前能否旋轉,就是預防快速點擊的時候跟不上。我在按下的時候把rotateFlag設置為false,然後在動畫結束後再把rotateFlag設置為true,但是好像作用並不明顯。。。希望有關大神可以指教一下。。。

 

本輪播插件下載地址:我的github!

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一、顯示信息的命令 console.log(); //控制台輸入 網頁中不會輸出 console.info(); //一般信息 console.debug(); //除錯信息 console.warn(); //警告提示 console.error(); //錯誤提示 “console.log(); ...
  • 註冊頁面是大多數網站必備的頁面,所以很有必要對自己的註冊頁面做些精心的設計。下麵三張圖,第一張是註冊的展示頁面,第二張思維導圖就一個簡單的邏輯,第三張是通過firebug查看調用的JS文件。 註冊的展示頁面 簡單的邏輯 通過firebug查看調用的JS文件 一、給每個輸入框寫下說明 在用戶看到這個輸 ...
  • 數據共用和數據傳遞是相輔相成的,我們一起來討論這個問題。首先要說的是共用和傳遞都是有作用域的。作用域就是起作用的區域,在同一個作用域數據可以共用,超過這個作用域就是跨作用域,就得用到數據傳遞了。 作用域 ui作用域每一個ui文件預設都有對應的ui.js。他們作為一個閉合的作用域。ui.js里根據ui ...
  • 學習要點: 1.HTML5 文檔結構 2.文檔結構解析 3.元素標簽探討 主講教師:李炎恢 本章主要先從 HTML5 的文檔結構談起。 這些基礎元素確定了 HTML 文檔的輪廓以及瀏覽器的初始環境。幾乎所有頁面都必須首先鍵入這些元素。 一.HTML5 文檔結構 1.第一步:打開 Sublime Te ...
  • 我們來個例子,一個HTML里包含一段文本和一個無序的列表。 上面例子里,我們使用getElementById DOM方法來訪問p段落,在SCRIPT里添加如下代碼: 變數introParagraph現在已經引用到該DOM節點上了,我們可以對該節點做很多事情,比如查詢內容和屬性,或者其它任何操作,甚至 ...
  • DOM
    DOM對象**1.屬性** docment.title 返回當前文檔的標題docment.URL 返迴文檔完整的URLdocument.bgColor 背景色document.fgColor 前景色 **2.方法** 2.1 document.getElementById(“elementID”); ...
  • 學習要點: 1.HTML5 的歷史 2.HTML5 的功能 3.HTML5 的特點 4.課程學習問題 主講教師:李炎恢 HTML5 是繼 HTML4.01 和 XHTML1.0 之後的超文本標記語言的最新版本。 它是由一群自由思想者組成的團隊設計出來,並最終實現多媒體支持、交互性、更加智能的表單,以 ...
  • 在bootstrap框架中將導航獨立出來成為一個導航組件,根據不同的版本,可以找到相應的源碼: LESS: navs.less SASS: _navs.scss 標簽形導航,也稱選項卡導航 標簽形導航是通過.nav-tabs樣式來實現的,在製作標簽形導航時需要在原導航類名為.nav的容器上追加類名. ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...