• 自制 移动端 纯原生 Slider滑动插件


    在Google搜关键字“slider”或“swiper”能找到一大堆相关插件,自己造轮子是为了能更好的理解其中的原理。

    给这个插件取名为“veSlider”是指“very easy slider”非常简单的一个滑动插件。

    这只是个半成品,仅仅实现了手指滑动、自动轮播、跳转等基本功能。代码撑死了200行不到,用的原理也比较简单粗暴。

    点击跳转到Github上代码地址。扫描下面的二维码可以查看在线demo:

    一、实现原理与效果

    1)在下图中,将“ul”容器设置为相对定位,子标签“li”设置为绝对定位

    2)移动的效果,其实就是动态修改translateX的值

    3)相邻的两张图片能够贴在一起,就是translateX起的作用

    4)动态给“li”添加或移除过渡效果,可以实现缓动

    5)当你向左滑动最后一张图片,跟着出来的是第一张;或者当你向右滑动第一张图片,跟着出来的是最后一张图片

    6)在第5点中,要实现这种效果需要做些控制,注意“li”标签最后会被设置为visibility,就是在做相关的控制,后面会讲到

    7)根据下图可以看到,当前的“li”的translateX值肯定是0,然后上一张为-320px,下一张320px

    二、结构

    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 //自动轮播间隔时间
    };

    三、实现代码

    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

    四、可以改进的部分

    1、CSS可以有更多的效果,也可以嵌入到JavaScript中

    2、li标签可以用JS脚本输出,而不用写死在页面中

    3、支持数组初始化,例如container设置为通过“getElementsByTagName”获取到的数组

    4、支持更多的自定义参数设置,目前只有4个

    5、浏览器兼容性,目前只支持webkit内核相关的

    6、在各个事件里,可以有自己定义的事件

    7、目前只支持左右滑动,上下滑动的话要做些更灵活的修改

    还有很多方面可以改进,这里就不列举了。

     

     

     

  • 相关阅读:
    [原创]测试计划与测试方案区别
    [原创]什么是构建验证测试(BVT)
    [原创]什么是测试驱动开发?
    [原创]用TestDirector的测试管理的流程
    [原创]测试用例设计之"正面测试与和负面测试"
    [原创]测试用例设计之“因果图”法
    [原创]测试用例设计之“状态迁移图”法
    [转贴]测试工具自动化的最佳实践
    [原创]软件测试管理之“测试角色和职能”概述
    软件测试试题
  • 原文地址:https://www.cnblogs.com/strick/p/5297491.html
Copyright © 2020-2023  润新知