欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

深入解析js輪播插件核心代碼的實現(xiàn)過程

 更新時間:2017年04月14日 11:00:24   作者:bjtqti  
這篇文章主要深度揭密了js輪播插件核心代碼的實現(xiàn)過程,具有一定的參考價值,感興趣的小伙伴們可以參考一下

輪播效果在網(wǎng)頁中用的很多,swiper是其中最有代表性的作品,它支持水平和豎直滑動,還有反彈效果,兼容移動端和pc端。當(dāng)然代碼量也是相當(dāng)大的,單是js就有5300行(3.4.0的未縮版本),若不考慮代碼利用率和加載速度直接就用了,在移動端比較慎重,比如京東(m.jd.com)的輪播就沒有用它,而是自己實現(xiàn)了類似的功能,代碼量很少的樣子(格式化之后看起來二三百行左右的樣子)。那么這個功能如果自己來實現(xiàn),要怎么做呢?

準(zhǔn)備工作

1. 準(zhǔn)備幾張圖片(我這里放了四張)

2. 搭建目錄結(jié)構(gòu)(html+css+images+js)

3. 編寫代碼,實現(xiàn)初始狀態(tài)的顯示效果

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
  <title>輪播</title>
  <link rel="stylesheet" type="text/css" href="slider.css" rel="external nofollow" >
  <script src="slider.js"></script>
</head>
<body>
  <div id="slider" class="slider-wrapper">
    <ul class="slider-items">
      <li class="slider-item"><img src="images/pic21.gif" alt="1"></li>
      <li class="slider-item"><img src="images/pic22.gif" alt="2"></li>
      <li class="slider-item"><img src="images/pic23.gif" alt="3"></li>
      <li class="slider-item"><img src="images/pic24.gif" alt="4"></li>
    </ul>
  </div>
  <script>
    Slider('#slider',{});
  </script>
</body>
</html>

寫幾行樣式,先讓頁面有一種滾動前的初始畫面。

body {
  padding: 0;
  min-width: 300px;
  max-width: 640px;
  margin: 0 auto;
}
 
ul {
  list-style: none;
}
 
ul,li {
  margin: 0;
  padding: 0;
}
 
.slider-wrapper {
  position: relative;
  width: 100%;
  height: 220px;
  overflow: hidden;
  -webkit-user-select: none;
  -ms-user-select: none;
  user-select: none;
}
 
.slider-items {
  position: relative;
  height: 100%;
}
 
.slider-item {
  float: left;
  text-align: center;
  cursor: pointer;
}
 
.slider-item > img {
  width: 100%;
  pointer-events: none;
}
 
.slider-pagination {
  position: absolute;
  bottom: 10px;
  left: 0;
  width: 100%;
  text-align: center;
  -webkit-transition-duration: .3s;
  -moz-transition-duration: .3s;
  -o-transition-duration: .3s;
  transition-duration: .3s;
}
 
.slider-bullet {
  width: 8px;
  height: 8px;
  margin: 0 5px;
  display: inline-block;
  border-radius: 100%;
  background-color: black;
  opacity: .2;
  cursor: pointer;
}
 
.slider-bullet-active {
  opacity: 1;
  background-color: #007aff;
}
 
.slider-button {
  position: absolute;
  top: 50%;
  width: 50px;
  height: 50px;
  text-align: center;
  line-height: 50px;
  margin-top: -25px;
  z-index: 10;
  font-size: 4rem;
  color: gray;
  -webkit-user-select:none;
  user-select:none;
}
 
.next {
  right: 0px;
}
 
.prev {
  left: 0px;
}

做好這個靜態(tài)頁,可以幫助我們在開發(fā)過程中預(yù)覽效果,方便查找問題,欣賞制作過程帶來的樂趣。

在線預(yù)覽

搭建程序骨架

接下來就是寫js了,先搭一個程序的架子,我這里仿一下jQ的無new式設(shè)計(其實是自己在內(nèi)部自動實現(xiàn)new的過程)

;( function( global, factory ) {
  "use strict";
  if ( typeof module === "object" && typeof module.exports === "object" ) {
    module.exports = global.document ?
      factory( global, true ) :
      function( w ) {
        if ( !w.document ) {
          throw new Error( "Slider requires a window with a document" );
        }
        return factory( w );
      };
  } else {
    factory( global );
  }
 
// Pass this if window is not defined yet
} )( typeof window !== "undefined" ? window : this, function( window, noGlobal ){
  "use strict";
     function Slider( selector, options ) {
    return new Slider.init( selector, options );
  }
  Slider.init=function(selector, params){
        next:function(){},<br>       prev:function(){},<br>       move:function(){}
    }<br>     Slider.init.prototype = Slider.prototype = {<br>      <br>    };
    return Slider
});

架子搭好之后,先停下來喝口水,思考一下,最終我們的這個插件要實現(xiàn)哪些功能。

    1. 點擊左、右箭頭可以控制滾動

    3. 可以向左、向右拖拽滑動

    4. 返彈效果

    5. 自動輪播效果

    6. 頁碼指示

這些功能該怎么實現(xiàn)?

先畫幾張圖,在紙上模擬一下這個過程,搞明白之后,再用代碼來讓計算機執(zhí)行。下圖中的藍(lán)框代表顯示器的寬度,紅框代表圖片所在容器的實際寬度。我只要移動紅框,那么在屏幕上看起來,就會有輪播滾動的效果。原理看起來是不是很簡單?本著先易后難,循序漸進(jìn)的作戰(zhàn)方針,先不考慮循環(huán)滾動。假設(shè)屏幕上顯示的是圖片1,此時只要把紅框往左移一個屏的寬度,那么就會顯示2,再移一屏,就可以顯示3. 向右滾動正好相反。

移動可以用css3的transform:translate3d來做,也可以用js變化left/top來做,用translate3d來做的核心代碼如下:

function translate3d(element,x,y) {
    x = x === undefined ? 0 : x;
    y = y === undefined ? 0 : x;
    element.style['-webkit-transform'] = 'translate3d(-'+x+'px,'+y+'px,0px)';
    element.style['transform'] = 'translate3d(-'+x+'px,'+y+'px,0px)';
  }
   
  function transition(element,time){
    element.style['-webkit-transition-duration'] = time+'ms';
    element.style['transition-duration'] = time+'ms';
  }

x控制左右移動,y控制豎直移動(本例中暫不考慮),z固定(0px). 當(dāng)x移動的距離是正數(shù)的時候,向左滾動--prev,為負(fù)數(shù)的時候向右滾動--next

fn.next = function(){
    var activeIndex = ++this.activeIndex;
    translate3d(this.wrap,activeIndex*this.slideWidth);
    transition(this.wrap,this.params.speed);
  }
 
fn.prev = function(){
    var activeIndex = --this.activeIndex;
    translate3d(this.wrap,activeIndex*this.slideWidth);
    transition(this.wrap,this.params.speed);
  }

由于圖片數(shù)量是有限的,不能一直滾動,如果到頭了,需要做一些處理。因此需要判斷activeIndex(當(dāng)前顯示的圖片索引)的值。如果到了最右邊就不能再允許滾動了。

var activeIndex = this.lastIndex--;<br>if(activeIndex > this.lastIndex){
   return;
}

同理,到了最左邊,也不能繼續(xù)往左滾動了(聽起來是一句非常正確的廢話)

var activeIndex = --this.activeIndex;
if(activeIndex < this.firstIndex){
  return;
}

現(xiàn)在要考慮自動滾動的情況,如果是自動輪播的情況,那就不能直接return; 要么當(dāng)?shù)竭_(dá)最右邊的時候,activeIndex賦成firstIndex,當(dāng)達(dá)到最左邊的時候,activeIndex賦成lastIndex; 這樣做的實際效果看起來就是像蕩秋千一樣,這顯然不是我們想要的效果。要么跳到最前面重新開始,這做出來的實際效果一點也不連續(xù)。最后決定去看看swiper是怎么實現(xiàn)的。swiper的做法就是把第一張復(fù)制一份放到最后面,把最后一張復(fù)制一份到最前面?!∪缦聢D所示:

第一張和第四張都被復(fù)制了一份。對應(yīng)的代碼如下:

fn.createLoopItems = function(){
    var lastItem = this.slides[this.lastIndex];
    var firstItem = this.slides[this.firstIndex];
    var prevItem = lastItem.cloneNode(true);
    var nextItem = firstItem.cloneNode(true);
    var sliderCount = this.sliderCount+2;
    var slideWidth = this.slideWidth;
    this.slideStack.push(this.firstIndex);
    this.slideStack.unshift(this.lastIndex);
    this.wrap.insertBefore(prevItem,firstItem);
    this.wrap.appendChild(nextItem);
    this.wrap.style.width = slideWidth * sliderCount + 'px';
    translate3d(this.wrap,slideWidth);
    this.activeIndex += 1;
    this.sliderCount = sliderCount;
    this.lastIndex += 2;
  }

不得不承認(rèn)這個做法很巧妙。隨便我們往哪個方向翻,都不至于出現(xiàn)空白期。當(dāng)翻到最未尾(數(shù)字4)的時候,還可以再翻一頁,即第一張的復(fù)制品,雖然不是真的第一張,但是看起來就像是平滑的過渡到了第一張一樣。不過這是臨時的,我們需要在過渡完之后,立即回到真正的1的位置上去。因為我們實際上在未端只補了一張,翻完這一頁,如果不進(jìn)一步處理,還是會到頭。這時,就是問題的關(guān)鍵了。當(dāng)我們往右翻,從第四張翻到復(fù)制的第一張時,需要悄悄地,人不知,鬼不覺的把紅框的位置移到1的真身上來。同時把activeIndex也置為圖1的索引。那么問題又來了,怎么才能做到人不知鬼不覺的暗渡陳倉呢?其實很簡單,只要把移位動畫的時間改成0就可以了。關(guān)鍵代碼如下:

transition(this.wrap,0);

不過這一步要在從4變?yōu)?,剛停下來的時候,立即執(zhí)行。做早了,就會感覺是直接從4跳到1,沒有動畫效果,做晚了,就會出現(xiàn)空白,并因為索引溢出而報錯。所以這里需要一個修復(fù)方法:

fn.fixedPrevLoop = function(){
    var that = this;
    setTimeout(function(){
      that.fixedLoop(that.lastIndex-1)
    },that.params.speed);
  }

或者:

this.container.addEventListener('transitionend',function(){
   

//動畫結(jié)速之后再執(zhí)行判斷是否要修復(fù)
},false);

做完這一步,就看起來有連續(xù)滾動的效果了,在這個基礎(chǔ)上實現(xiàn)自動輪播就好辦了,只要用定時器,每隔一段時間就執(zhí)行一下自身就可以了。代碼如下:

fn.autoPlay = function(){
    var that = this;
    if(!this.params.autoplay){
      return;
    }
    this.timeId = setTimeout(function(){
      that.next();
      //that.prev();
      that.autoPlay();
    },this.params.delay);
  }

  我注釋掉了prev(), 默認(rèn)都是向右自動輪播。如果要改成是往左輪播,只要在這里加一個一個配置選擇就好了。自動循環(huán)都做好了,在此基礎(chǔ)上點擊翻頁,也是很容易的事情了,給按鈕邦定一個click事件,如果是右邊的,就調(diào)用next()方法,反之則調(diào)用prev()方法。不過我這里沒有這樣做,因為考慮到后面我們還要做手勢(鼠標(biāo))拖動翻頁效果,我決定用事件來做。讓事件統(tǒng)統(tǒng)都冒泡到包裝容器上去處理,這也是提升性能的常用技巧之一。

fn.bindEvents = function(){
    if(Device.desktop){
      this.container.addEventListener('mousedown',this,false);
      this.container.addEventListener('mousemove',this,false);
      document.addEventListener('mouseup',this,false);
    }else{
      this.container.addEventListener('touchstart',this,false);
      this.container.addEventListener('touchmove',this,false);
      document.addEventListener('touchend',this,false);
    }
    this.container.addEventListener('transitionend',this,false);
    this.container.addEventListener('click',this,false);
  }

  為什么這里的addEventListener為什么是邦定this而不是一個函數(shù)呢?簡單說,是因為上下文中有一個handleEvent方法,可以被函數(shù)自動捕獲到,這個函數(shù)名是固定的,不明白的可以自行搜索這個函數(shù)名。

fn.handleEvent = function(e){
    var type = e.type;<br>  //注意這里邊的this<br>}

這樣做的好處是可以維持事件邦定的那個函數(shù)的上下文。簡單說就是不用操心this的指向會變。

做完這一步,就可以做拖動翻頁了。在pc上用鼠標(biāo),在手機上用手指,處理的方式都是一樣的,按下,移動,釋放這三個事件。按下的時候,記住初始坐標(biāo),移動的時候和這個坐標(biāo)進(jìn)行對比,計算出移動的距離,然后更新到移動的對象上(紅框)。這里邊有幾個地方需要注意:

1. 如果移動的時候,不是直線,x坐標(biāo)和y坐標(biāo)都有改變,是判斷成水平拖動還是垂直拖動?

2. 在pc上,如何判斷是拖動,拖出屏幕外了怎么處理?

3. 反彈怎么做?

對于第1點,可以比較兩個方向距離的大小,誰大聽誰的。如果指向了是水平滾動,那么可以直接忽略豎直方向的變化。

對于第2點,可以把mouseup放到document上去,最好加一個移動的距離大小判斷,如果超過容器的大小,就當(dāng)作是釋放了,該反彈的反彈,該滑頁的滑頁。

對于第3點,在拖動釋放的時候,判斷移動距離,比如拖動的距離小于屏寬的1/3,就反方向translate相應(yīng)的距離回去,甚至都不用關(guān)心這個距離,反正這時的activeIndex沒有更新的,直接回到這個activeIndex對應(yīng)的頁就算是反彈了。代碼就是這樣:

fn.stop = function(){
    this.axis.x = 0;
    translate3d(this.wrap,this.slideWidth*this.activeIndex);
    transition(this.wrap,this.params.speed);
}

接下來就是做頁碼指示器了,這個簡單,翻頁成功之后就更新一下對應(yīng)的小點就是了。由于我們?nèi)藶榈牟辶藘蓚€頁面進(jìn)去,索引數(shù)和頁碼數(shù)就對應(yīng)不起來了,實際參與滾動的圖片有6張,但是只能顯示4個點。我做的時候走了一些彎路,現(xiàn)在總結(jié)起來無非就是兩點:

1. 給小圓點加一個屬性用來標(biāo)記是哪個頁面。用于處理點擊滾動的時候,知道是跳到哪個頁面。

2. 用一個數(shù)組來保存頁面索引,比如【3,0,1,2,3,1】,這樣當(dāng)自動或拖動翻頁的時候,可以通過activeIndex的值,確定要高亮哪個頁碼指示器。(小圓點)

也可能還有更好的方法,暫時就先這樣實現(xiàn)吧。先把功能做出來,后面有時間,有靈感了再去優(yōu)化。

到這里,幾本上就做完了,只是還要再完善一些邊際情況,比如一張圖都沒有的情況,默認(rèn)參數(shù)的處理等。

思考

除了這個方法之外是不是有其它解決方法呢?比如下圖這樣,紅框中只放三張,多余的疊在屏后面,移動的時候不是移紅框,而是真實的移動圖片?

 這種方法也是可以行的通的,不過我在嘗試的時候,發(fā)現(xiàn)這種方法在手機上有些卡頓,在電腦上看,容器邊框會有閃動,原因沒有深入去查了。

  咳!咳..,下載源碼請上github.com  ,在線預(yù)覽無圖片版本

小結(jié)一下

寫到這里的時候,主體的邏輯差不多就實現(xiàn)了, 只用了大約三百多行代碼,雖然很精簡,但是這里還有許多東西沒有考慮進(jìn)去,比如豎直方向的滾動,兼容性問題等等。通過畫圖的方法來幫助理清思路,遇到困難,可以借鑒別人的實現(xiàn)方法,參考但不是原封不動的復(fù)制粘貼。代碼組織要考慮擴展性和可讀性,先從程序的骨架寫起,然后再去寫方法,處理細(xì)節(jié)問題。通過動手實踐,可以發(fā)現(xiàn)一些看似簡單的東西,做起來也不是那么容易的。自己做出來之后,再去看別人寫的好的代碼,就會知道人家哪些地方比我實現(xiàn)的好,有哪些值得學(xué)習(xí)的地方。

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • javascript 像素拼圖實現(xiàn)代碼

    javascript 像素拼圖實現(xiàn)代碼

    非常不錯的像素拼圖效果
    2009-04-04
  • Echarts折線圖設(shè)置線條顏色及線條以下代碼示例

    Echarts折線圖設(shè)置線條顏色及線條以下代碼示例

    最近項目需要,一直在使用Echarts視圖,現(xiàn)在遇到一個要修改echarts折線圖顏色的需求,下面這篇文章主要給大家介紹了關(guān)于Echarts折線圖設(shè)置線條顏色及線條以下區(qū)域漸變顏色的相關(guān)資料,需要的朋友可以參考下
    2024-02-02
  • JavaScript代碼判斷輸入的字符串是否含有特殊字符和表情代碼實例

    JavaScript代碼判斷輸入的字符串是否含有特殊字符和表情代碼實例

    這篇文章主要介紹了JavaScript代碼判斷輸入的字符串是否含有特殊字符和表情,通過js代碼if語句進(jìn)行判斷,并結(jié)合自己開發(fā)的情景,具體操作步驟大家可查看下文的詳細(xì)講解,感興趣的小伙伴們可以參考一下。
    2017-08-08
  • JavaScript變量中var,let和const的區(qū)別

    JavaScript變量中var,let和const的區(qū)別

    這篇文章主要介紹了JavaScript變量中var,let和const的區(qū)別,JavaScript中一共有3種用來聲明變量的關(guān)鍵字,分別是var、let和const,文章通過圍繞主題展開對三個關(guān)鍵詞的詳細(xì)介紹,需要的朋友可以參考一下
    2022-09-09
  • JavaScript實現(xiàn)圖像模糊化的方法實例

    JavaScript實現(xiàn)圖像模糊化的方法實例

    這篇文章主要介紹了JavaScript實現(xiàn)圖像模糊化的方法,文中先進(jìn)行簡單介紹,而后給出了完整的實例代碼,有需要的朋友可以參考借鑒,下面來一起看看吧。
    2017-01-01
  • JavaScript 隨機驗證碼的生成實例代碼

    JavaScript 隨機驗證碼的生成實例代碼

    這篇文章主要介紹了JavaScript 隨機驗證碼的生成實例代碼的相關(guān)資料,需要的朋友可以參考下
    2016-09-09
  • 原生js編寫貪吃蛇小游戲

    原生js編寫貪吃蛇小游戲

    這篇文章主要為大家詳細(xì)介紹了原生js編寫貪吃蛇小游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-05-05
  • 詳解JSON和JSONP劫持以及解決方法

    詳解JSON和JSONP劫持以及解決方法

    這篇文章主要介紹了詳解JSON和JSONP劫持以及解決方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-03-03
  • JS實現(xiàn)將數(shù)字金額轉(zhuǎn)換為大寫人民幣漢字的方法

    JS實現(xiàn)將數(shù)字金額轉(zhuǎn)換為大寫人民幣漢字的方法

    這篇文章主要介紹了JS實現(xiàn)將數(shù)字金額轉(zhuǎn)換為大寫人民幣漢字的方法,涉及javascript字符串與數(shù)組操作的相關(guān)技巧,需要的朋友可以參考下
    2016-08-08
  • 利用JS實現(xiàn)點擊按鈕后圖片自動切換的簡單方法

    利用JS實現(xiàn)點擊按鈕后圖片自動切換的簡單方法

    下面小編就為大家?guī)硪黄肑S實現(xiàn)點擊按鈕后圖片自動切換的簡單方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-10-10

最新評論