自制 移動端 純原生 Slider滑動插件

在Google搜關鍵字「slider」或「swiper」能找到一大堆相關插件,本身造輪子是爲了能更好的理解其中的原理。html

給這個插件取名爲「veSlider」是指「very easy slider」很是簡單的一個滑動插件。git

這只是個半成品,僅僅實現了手指滑動、自動輪播、跳轉等基本功能。代碼撐死了200行不到,用的原理也比較簡單粗暴。github

點擊跳轉到Github上代碼地址。掃描下面的二維碼能夠查看在線demo:web

 

1、實現原理與效果

1)在下圖中,將「ul」容器設置爲相對定位,子標籤「li」設置爲絕對定位數組

2)移動的效果,其實就是動態修改translateX的值瀏覽器

3)相鄰的兩張圖片可以貼在一塊兒,就是translateX起的做用緩存

4)動態給「li」添加或移除過渡效果,能夠實現緩動dom

5)當你向左滑動最後一張圖片,跟着出來的是第一張;或者當你向右滑動第一張圖片,跟着出來的是最後一張圖片ide

6)在第5點中,要實現這種效果須要作些控制,注意「li」標籤最後會被設置爲visibility,就是在作相關的控制,後面會講到函數

7)根據下圖能夠看到,當前的「li」的translateX值確定是0,而後上一張爲-320px,下一張320px

 

2、結構

1)CSS

只是作了簡單通用設置,能夠自定義擴充。

 1 .veSlider {
 2   position: relative;
 3   list-style: none;
 4   margin: 0;
 5   padding: 0;
 6   width: 100%;
 7   overflow: hidden;
 8 }
 9 .veSlider > li {
10   position: absolute;
11   top: 0;
12   left: 0;
13   list-style: none;
14   overflow: hidden;
15   height: inherit;
16 }

 

2)HTML

爲了實現方便,我直接將相關的ul與li標籤寫死在頁面中。

高級點的話,能夠經過JS腳本動態輸出,而且在輸出的時候能夠作圖片預加載等處理。

height寫在了style中,由於各類狀況下的高度是不一樣的,因此自定義設置

1 <ul class="veSlider" style="height:180px" id="veSlider">
2   <li>
3     <a href="http://www.cnblogs.com/strick/">
4       <img src="img/banner.jpg" width="100%" />
5     </a>
6   </li>
7 </ul>

 

3)JavaScript

經過new一個veSlider對象作初始化。

var slider = new veSlider({
  container: document.getElementById('veSlider')
});

目前能夠傳入的參數只有4個。容器container目前只支持單個的,例如上面的「getElementById」;不支持列表初始化,例如「getElementsByTagName」等

var defaults = {
  container: '', //容器對象
  auto: false, //自動輪播
  easing: 'ease-in', //緩動類型
  duration: 3000 //自動輪播間隔時間
};

 

3、實現代碼

1)插件封裝

如今有比較時髦的AMD、UMD模塊規範,爲了讓插件支持這些規範,須要作一些聲明。

爲了防止在引入其餘JS腳本的時候,將window或undefined重寫掉,會傳入原生的window與undefined。

;(function(factory) {
  /* CommonJS module. */
  if (typeof module === "object" && typeof module.exports === "object") {
    module.exports = factory(window);
    /* AMD module. */
  } else if (typeof define === "function" && define.amd) {
    define(factory(window));
    /* Browser globals. */
  } else {
    factory(window);
  }
}(function(global, undefined) {
  "use strict";
  
}));

 

2)構造函數

1. 默認參數與傳入的參數作合併

2. 一些值的初始化,例如容器container、偏移對象offset

3. 容器尺寸的獲取,經過方法「getBoundingClientRect」得到。關於尺寸獲取能夠參考《JavaScript中尺寸、座標

4. 給容器綁定事件,「touchstart」、「touchmove」等。事件綁定用到了「handleEvent」方式綁定。事件方面的資料能夠參考《JavaScript中事件處理

5. 獲取容器中的子集,並將這些子集的translateX值初始化

6. 初始化自動輪播。下面是部分代碼:

function veSlider(opts) {
  this.opts = extend(opts, defaults);//默認參數與傳入參數合併
  this.size = this.container.getBoundingClientRect(); //容器尺寸
  this.children = slice.call(this.container.children); //容器的子集
  this.currentIndex = 0; //當前索引
  this._bind(); //綁定動畫事件

  this.caculate(this.currentIndex); //初始化子集的偏移量
  this.opts.auto && this.play(); //初始化自動輪播
};

 

3)切換子集的判斷

在「touchend」事件中,作了簡單的判斷。

1. 對於慢速滑動,若是滑動的距離超過了當前容器的一半,那就作切換操做

2. 間隔時間在 300ms 內就算快速滑動,滑動距離只要超過 14,就作切換操做

3. 下圖第一次是慢速,第二次是快速

 

4)slideTo方法控制某個子集滑動到指定位置

veSliderProtytype.slideTo = function(index, time) {
  this.currentIndex = index = this._setThreshold(index);
  var other = this.direction == CONST.LEFT ? (index - 1) : (index + 1);
  other = this._setThreshold(other);

  //隱藏須要移動的子集
  this.children.forEach(function(dom, i) {
    if (i == index || i == other) {
      return;
    }
    dom.style.visibility = 'hidden';
  });
  //手指移動的時候用.1 自動移動的時候用.4
  this.caculate(index, time || '.1');
};

1. 傳入當前的子集索引,而後根據_setThreshold方法獲取到正確的索引值

2. _setThreshold控制「<0」的數設置爲0,「>last」也就是最大索引值的數,設置爲last

3. 給other值賦值,根據緩存的direction方向,判斷貼在一塊兒的子集是上一個仍是下一個,一樣也要作_setThreshold判斷

4. 隱藏會移動的圖片,這個代碼就是用來解決上面「實現原理與效果」中第6點提到的問題

5. 下圖是演示若是不隱藏會出現的問題,滑動的時候出現了最後那張圖片

5. 最後作位移計算

 

 

5)caculate方法計算偏移值

veSliderProtytype.caculate = function(index, time, offsetX) {
  var _this = this, last = this.last;
  this.children.forEach(function(dom, i) {
    var x = i - index;
    if (index == 0 && i == last) {
      x = -1;
    } else if (index == last && i == 0) {
      x = 1;
    }
    setTransition(dom, _this.opts.easing, time);
    setTranslateX(dom, x, _this.size, offsetX || 0);
  });
};

1. 計算相對當前子集的尺寸偏移倍數,經過「i - index」取得值

2. 再判斷當前子集是第一個或最後一個,這兩個位置比較特殊

3. 設置過渡與translateX的相關值

4. 偏移值是經過計算的「offsetX + size.width * i」,容器寬度的倍數加上當前移動的距離

5. 以容器寬度爲320px爲例,經過上面的計算,可讓當前子集translateX爲0,前一張爲-320px,後一張爲320px,再後一張就是兩倍640px

 

4、能夠改進的部分

一、CSS能夠有更多的效果,也能夠嵌入到JavaScript中

二、li標籤能夠用JS腳本輸出,而不用寫死在頁面中

三、支持數組初始化,例如container設置爲經過「getElementsByTagName」獲取到的數組

四、支持更多的自定義參數設置,目前只有4個

五、瀏覽器兼容性,目前只支持webkit內核相關的

六、在各個事件裏,能夠有本身定義的事件

七、目前只支持左右滑動,上下滑動的話要作些更靈活的修改

還有不少方面能夠改進,這裏就不列舉了。

相關文章
相關標籤/搜索