zoukankan      html  css  js  c++  java
  • flipsnap.js 源码阅读备份

    这是官网:http://hokaccha.github.io/js-flipsnap/

    1.引入全局命名空间 类似jQuery插件写法   传入window, document,提高内部访问速度;

    ;(function(window, document, undefined){})(window, window.document)
     

    2.定义全局变量

    /* 新建div节点 */
    var div = document.createElement('div');
    /* 浏览器前缀 */
    var prefix = ['webkit', 'moz', 'o', 'ms'];
    /* 存储属性对象 */
    var saveProp = {};
    /* 检测浏览器支持的对象 */
    var support = Flipsnap.support = {};
    /* 手势状态判断 */
    var gestureStart = false;
    /* 阀值设置 */
    var DISTANCE_THRESHOLD = 5;
    var ANGLE_THREHOLD = 55;
     

    3.分别检测对transform3d, transform及trasition 3个css3属性的支持程度

    support.transform3d = hasProp([
      'perspectiveProperty',
      'WebkitPerspective',
      'MozPerspective',
      'OPerspective',
      'msPerspective'
    ]);
    support.transform = hasProp([
      'transformProperty',
      'WebkitTransform',
      'MozTransform',
      'OTransform',
      'msTransform'
    ]);
    support.transition = hasProp([
      'transitionProperty',
      'WebkitTransitionProperty',
      'MozTransitionProperty',
      'OTransitionProperty',
      'msTransitionProperty'
    ]);

    使用hasProp()函数

    function hasProp(props) {
      return some(props, function(prop) {
        return div.style[ prop ] !== undefined;
      });
    }

    其中some()闭包函数##为,只要数组内其中一个为true即判定为true

    function some(ary, callback) {
      for (var i = 0, len = ary.length; i < len; i++) {
        if (callback(ary[i], i)) {
          return true;
        }
      }
      return false;
    }
     

    4.其他浏览器的属性支持(事件监听属性及IE的指针事件的支持)及总的css动画属性支持判断

    support.addEventListener = 'addEventListener' in window;
    support.mspointer = window.navigator.msPointerEnabled;
    support.cssAnimation = (support.transform3d || support.transform) && support.transition;

    5.定义事件种类及相关事件对象

    var eventTypes = ['touch', 'mouse'];
    var events = {
      start: {
        touch: 'touchstart',
        mouse: 'mousedown'
      },
      move: {
        touch: 'touchmove',
        mouse: 'mousemove'
      },
      end: {
        touch: 'touchend',
        mouse: 'mouseup'
      }
    };

    6.添加事件监听

    if (support.addEventListener) {
      document.addEventListener('gesturestart', function() {
        gestureStart = true;
      });
      document.addEventListener('gestureend', function() {
        gestureStart = false;
      });
    }

    7.定义全局新类Flipsnap(),并初始化新类,其中使用了Flipsnap类的初始方法init()

    function Flipsnap(element, opts) {
      return (this instanceof Flipsnap)
        ? this.init(element, opts)
        : new Flipsnap(element, opts);
    }

    8.定义Flipsnap类的初始化方法init()

    Flipsnap.prototype.init = function(element, opts) {
      var self = this;
      // set element
      self.element = element;
      if (typeof element === 'string') {
        self.element = document.querySelector(element);
      }
      if (!self.element) {
        throw new Error('element not found');
      }
      if (support.mspointer) {
        self.element.style.msTouchAction = 'pan-y';
      }
      // set opts
      opts = opts || {};
      self.distance = opts.distance;
      self.maxPoint = opts.maxPoint;
      self.disableTouch = (opts.disableTouch === undefined) ? false : opts.disableTouch;
      self.disable3d = (opts.disable3d === undefined) ? false : opts.disable3d;
      self.transitionDuration = (opts.transitionDuration === undefined) ? '350ms' : opts.transitionDuration + 'ms';
      self.threshold = opts.threshold || 0;
      // set property
      self.currentPoint = 0;
      self.currentX = 0;
      self.animation = false;
      self.use3d = support.transform3d;
      if (self.disable3d === true) {
        self.use3d = false;
      }
      // set default style
      if (support.cssAnimation) {
        self._setStyle({
          transitionProperty: getCSSVal('transform'),
          transitionTimingFunction: 'cubic-bezier(0,0,0.25,1)',
          transitionDuration: '0ms',
          transform: self._getTranslate(0)
        });
      }
      else {
        self._setStyle({
          position: 'relative',
          left: '0px'
        });
      }
      // initilize
      self.refresh();
      eventTypes.forEach(function(type) {
        // 为什么要传人self作回调函数,(self=Flipsnap())?
        self.element.addEventListener(events.start[type], self, false);
      });
      return self;
    };

    其中_setStyle()为FLipsnap的内部方法

    Flipsnap.prototype._setStyle = function(styles) {
      var self = this;
      var style = self.element.style;
      for (var prop in styles) {
        setStyle(style, prop, styles[prop]);
      }
    };

    其中setStyle()函数,设置对应css属性为对应值,具体为

    function setStyle(style, prop, val) {
      var _saveProp = saveProp[ prop ];
      if (_saveProp) {
        style[ _saveProp ] = val;
      }
      else if (style[ prop ] !== undefined) {
        saveProp[ prop ] = prop;
        style[ prop ] = val;
      }
      else {
        some(prefix, function(_prefix) {
          var _prop = ucFirst(_prefix) + ucFirst(prop);
          if (style[ _prop ] !== undefined) {
            saveProp[ prop ] = _prop;
            style[ _prop ] = val;
            return true;
          }
        });
      }
    }

    并在saveProp中设置过的属性

    getCSSVal()函数用于获取已用的css属性值,具体如下

    function getCSSVal(prop) {
      if (div.style[ prop ] !== undefined) {
        return prop;
      }
      else {
        var ret;
        some(prefix, function(_prefix) {
          var _prop = ucFirst(_prefix) + ucFirst(prop);
          if (div.style[ _prop ] !== undefined) {
            ret = '-' + _prefix + '-' + prop;
            return true;
          }
        });
        return ret;
      }
    }

    ucFirst()函数用于将首字母变大写,具体如下 截取第一个字符串charAt(0)转为大写 拼接后面剩下的字符串(substr(1))

    function ucFirst(str) {
      return str.charAt(0).toUpperCase() + str.substr(1);
    }
     

    self._getTranslate为Flipsnap的内部方法

    Flipsnap.prototype._getTranslate = function(x) {
      var self = this;
      return self.use3d
        ? 'translate3d(' + x + 'px, 0, 0)'
        : 'translate(' + x + 'px, 0)';
    };

    refresh()的Flipsnap方法,具体如下

    Flipsnap.prototype.refresh = function() {
      var self = this;
      // setting max point
      self._maxPoint = (self.maxPoint === undefined) ? (function() {
        var childNodes = self.element.childNodes,
          itemLength = -1,
          i = 0,
          len = childNodes.length,
          node;
        for(; i < len; i++) {
          node = childNodes[i];
          if (node.nodeType === 1) {
            itemLength++;
          }
        }
        return itemLength;
      })() : self.maxPoint;
      // setting distance
      if (self.distance === undefined) {
        if (self._maxPoint < 0) {
          self._distance = 0;
        }
        else {
          self._distance = self.element.scrollWidth / (self._maxPoint + 1);
        }
      }
      else {
        self._distance = self.distance;
      }
      // setting maxX
      self._maxX = -self._distance * self._maxPoint;
      self.moveToPoint();
    };

    通过refresh方法设定_maxPoint(最多移动次数)、_distance(移动距离)和_maxX(最大x轴偏向值)属性,从而控制最多的滑动次数;

    moveToPoint()的Flipsnap方法,判定是否需要滑动并触发事件,具体如下

    Flipsnap.prototype.moveToPoint = function(point, transitionDuration) {
      var self = this;
      transitionDuration = transitionDuration === undefined
        ? self.transitionDuration : transitionDuration + 'ms';
      var beforePoint = self.currentPoint;
      // not called from `refresh()`
      if (point === undefined) {
        point = self.currentPoint;
      }
      if (point < 0) {
        self.currentPoint = 0;
      }
      else if (point > self._maxPoint) {
        self.currentPoint = self._maxPoint;
      }
      else {
        self.currentPoint = parseInt(point, 10);
      }
      if (support.cssAnimation) {
        self._setStyle({ transitionDuration: transitionDuration });
      }
      else {
        self.animation = true;
      }
      self._setX(- self.currentPoint * self._distance, transitionDuration);
      if (beforePoint !== self.currentPoint) { // is move?
        // `fsmoveend` is deprecated
        // `fspointmove` is recommend.
        self._triggerEvent('fsmoveend', true, false);
        self._triggerEvent('fspointmove', true, false);
      }
    };

    其中_setX()为Flipsnap的内部方法,具体如下

    Flipsnap.prototype._setX = function(x, transitionDuration) {
      var self = this;
      self.currentX = x;
      if (support.cssAnimation) {
        self.element.style[ saveProp.transform ] = self._getTranslate(x);
      }
      else {
        if (self.animation) {
          self._animate(x, transitionDuration || self.transitionDuration);
        }
        else {
          self.element.style.left = x + 'px';
        }
      }
    };

    其中_animate()为Flipsnap的内部方法,具体如下

    Flipsnap.prototype._animate = function(x, transitionDuration) {
      var self = this;
      var elem = self.element;
      var begin = +new Date();
      var from = parseInt(elem.style.left, 10);
      var to = x;
      var duration = parseInt(transitionDuration, 10);
      var easing = function(time, duration) {
        return -(time /= duration) * (time - 2);
      };
      var timer = setInterval(function() {
        var time = new Date() - begin;
        var pos, now;
        if (time > duration) {
          clearInterval(timer);
          now = to;
        }
        else {
          pos = easing(time, duration);
          now = pos * (to - from) + from;
        }
        elem.style.left = now + "px";
      }, 10);
    };

    其中_triggerEvent() 为Flipsnap的内部方法,具体如下

    Flipsnap.prototype._triggerEvent = function(type, bubbles, cancelable, data) {
      var self = this;
      var ev = document.createEvent('Event');
      ev.initEvent(type, bubbles, cancelable);
      if (data) {
        for (var d in data) {
          if (data.hasOwnProperty(d)) {
            ev[d] = data[d];
          }
        }
      }
      return self.element.dispatchEvent(ev);
    };

    9.定义Flipsnap类的事件控制方法handleEvent()

    Flipsnap.prototype.handleEvent = function(event) {
      var self = this;
      switch (event.type) {
        // start
        case events.start.touch: self._touchStart(event, 'touch'); break;
        case events.start.mouse: self._touchStart(event, 'mouse'); break;
        // move
        case events.move.touch: self._touchMove(event, 'touch'); break;
        case events.move.mouse: self._touchMove(event, 'mouse'); break;
        // end
        case events.end.touch: self._touchEnd(event, 'touch'); break;
        case events.end.mouse: self._touchEnd(event, 'mouse'); break;
        // click
        case 'click': self._click(event); break;
      }
    };

    通过event.type进行条件判断,确定执行Flipsnap的四个内部处理方法中的一个

    _touchStart()方法

    Flipsnap.prototype._touchStart = function(event, type) {
      var self = this;
      if (self.disableTouch || self.scrolling || gestureStart) {
        return;
      }
      self.element.addEventListener(events.move[type], self, false);
      document.addEventListener(events.end[type], self, false);
      var tagName = event.target.tagName;
      if (type === 'mouse' && tagName !== 'SELECT' && tagName !== 'INPUT' && tagName !== 'TEXTAREA' && tagName !== 'BUTTON') {
        event.preventDefault();
      }
      if (support.cssAnimation) {
        self._setStyle({ transitionDuration: '0ms' });
      }
      else {
        self.animation = false;
      }
      self.scrolling = true;
      self.moveReady = false;
      self.startPageX = getPage(event, 'pageX');
      self.startPageY = getPage(event, 'pageY');
      self.basePageX = self.startPageX;
      self.directionX = 0;
      self.startTime = event.timeStamp;
      self._triggerEvent('fstouchstart', true, false);
    };

    通过touchStart方法记录下触摸开始点开始时间等参数,并触发fstouchstart事件;

    getPage()函数如下

    function getPage(event, page) {
      return event.changedTouches ? event.changedTouches[0][page] : event[page];
    }

    _touchMove()方法如下

    Flipsnap.prototype._touchMove = function(event, type) {
      var self = this;
      if (!self.scrolling || gestureStart) {
        return;
      }
      var pageX = getPage(event, 'pageX');
      var pageY = getPage(event, 'pageY');
      var distX;
      var newX;
      if (self.moveReady) {
        event.preventDefault();
        distX = pageX - self.basePageX;
        newX = self.currentX + distX;
        if (newX >= 0 || newX < self._maxX) {
          newX = Math.round(self.currentX + distX / 3);
        }
        // When distX is 0, use one previous value.
        // For android firefox. When touchend fired, touchmove also
        // fired and distX is certainly set to 0. 
        self.directionX =
          distX === 0 ? self.directionX :
          distX > 0 ? -1 : 1;
        // if they prevent us then stop it
        var isPrevent = !self._triggerEvent('fstouchmove', true, true, {
          delta: distX,
          direction: self.directionX
        });
        if (isPrevent) {
          self._touchAfter({
            moved: false,
            originalPoint: self.currentPoint,
            newPoint: self.currentPoint,
            cancelled: true
          });
        } else {
          self._setX(newX);
        }
      }
      else {
        // https://github.com/pxgrid/js-flipsnap/pull/36
        var triangle = getTriangleSide(self.startPageX, self.startPageY, pageX, pageY);
        if (triangle.z > DISTANCE_THRESHOLD) {
          if (getAngle(triangle) > ANGLE_THREHOLD) {
            event.preventDefault();
            self.moveReady = true;
            self.element.addEventListener('click', self, true);
          }
          else {
            self.scrolling = false;
          }
        }
      }
      self.basePageX = pageX;
    };

    其中getTriangleSide()函数如下

    function getTriangleSide(x1, y1, x2, y2) {
      var x = Math.abs(x1 - x2);
      var y = Math.abs(y1 - y2);
      var z = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
      return {
        x: x,
        y: y,
        z: z
      };
    }

    其中getAngle()函数如下

    function getAngle(triangle) {
      var cos = triangle.y / triangle.z;
      var radina = Math.acos(cos);
      return 180 / (Math.PI / radina);
    }

    _touchEnd()方法如下

    Flipsnap.prototype._touchEnd = function(event, type) {
      var self = this;
      self.element.removeEventListener(events.move[type], self, false);
      document.removeEventListener(events.end[type], self, false);
      if (!self.scrolling) {
        return;
      }
      var newPoint = -self.currentX / self._distance;
      newPoint =
        (self.directionX > 0) ? Math.ceil(newPoint) :
        (self.directionX < 0) ? Math.floor(newPoint) :
        Math.round(newPoint);
      if (newPoint < 0) {
        newPoint = 0;
      }
      else if (newPoint > self._maxPoint) {
        newPoint = self._maxPoint;
      }
      if (Math.abs(self.startPageX - self.basePageX) < self.threshold) {
        newPoint = self.currentPoint;
      }
      self._touchAfter({
        moved: newPoint !== self.currentPoint,
        originalPoint: self.currentPoint,
        newPoint: newPoint,
        cancelled: false
      });
      self.moveToPoint(newPoint);
    };

    触发fstouchend事件

    其中_touchAfter()方法如下

    Flipsnap.prototype._touchAfter = function(params) {
      var self = this;
      self.scrolling = false;
      self.moveReady = false;
      setTimeout(function() {
        self.element.removeEventListener('click', self, true);
      }, 200);
      self._triggerEvent('fstouchend', true, false, params);
    };

    _clic()方法如下

    Flipsnap.prototype._click = function(event) {
      var self = this;
      event.stopPropagation();
      event.preventDefault();
    };

    10.定义Flipsnap类的状态判断方法hasNext()

    Flipsnap.prototype.hasNext = function() {
      var self = this;
      return self.currentPoint < self._maxPoint;
    };

    11.定义Flipsnap类的状态判断方法hasPrev()

    Flipsnap.prototype.hasPrev = function() {
      var self = this;
      return self.currentPoint > 0;
    };

    12.定义Flipsnap类的跳转下一个方法toNext()

    Flipsnap.prototype.toNext = function(transitionDuration) {
      var self = this;
      if (!self.hasNext()) {
        return;
      }
      self.moveToPoint(self.currentPoint + 1, transitionDuration);
    };

    13.定义Flipsnap类的跳转上一个方法toPrev()

    Flipsnap.prototype.toPrev = function(transitionDuration) {
      var self = this;
      if (!self.hasPrev()) {
        return;
      }
      self.moveToPoint(self.currentPoint - 1, transitionDuration);
    };

    14.定义Flipsnap类的跳转上一个方法destroy()

    Flipsnap.prototype.destroy = function() {
      var self = this;
      eventTypes.forEach(function(type) {
        self.element.removeEventListener(events.start[type], self, false);
      });
    };

    取消在各个节点上的事件监听

    15.将Flipsnap模块化

    if (typeof exports == 'object') {
      module.exports = Flipsnap;
    }
    else if (typeof define == 'function' && define.amd) {
      define(function() {
        return Flipsnap;
      });
    }
    else {
      window.Flipsnap = Flipsnap;
    }

    /**
     * flipsnap.js
     *
     * @version  0.6.2
     * @url http://hokaccha.github.com/js-flipsnap/
     *
     * Copyright 2011 PixelGrid, Inc.
     * Licensed under the MIT License:
     * http://www.opensource.org/licenses/mit-license.php
     */
    
    (function(window, document, undefined) {
    
    var div = document.createElement('div');
    var prefix = ['webkit', 'moz', 'o', 'ms'];
    var saveProp = {};
    var support = Flipsnap.support = {};
    var gestureStart = false;
    
    var DISTANCE_THRESHOLD = 5;
    var ANGLE_THREHOLD = 55;
    
    support.transform3d = hasProp([
      'perspectiveProperty',
      'WebkitPerspective',
      'MozPerspective',
      'OPerspective',
      'msPerspective'
    ]);
    
    support.transform = hasProp([
      'transformProperty',
      'WebkitTransform',
      'MozTransform',
      'OTransform',
      'msTransform'
    ]);
    
    support.transition = hasProp([
      'transitionProperty',
      'WebkitTransitionProperty',
      'MozTransitionProperty',
      'OTransitionProperty',
      'msTransitionProperty'
    ]);
    
    support.addEventListener = 'addEventListener' in window;
    support.mspointer = window.navigator.msPointerEnabled;
    
    support.cssAnimation = (support.transform3d || support.transform) && support.transition;
    
    var eventTypes = ['touch', 'mouse'];
    var events = {
      start: {
        touch: 'touchstart',
        mouse: 'mousedown'
      },
      move: {
        touch: 'touchmove',
        mouse: 'mousemove'
      },
      end: {
        touch: 'touchend',
        mouse: 'mouseup'
      }
    };
    
    if (support.addEventListener) {
      document.addEventListener('gesturestart', function() {
        gestureStart = true;
      });
    
      document.addEventListener('gestureend', function() {
        gestureStart = false;
      });
    }
    
    function Flipsnap(element, opts) {
      return (this instanceof Flipsnap)
        ? this.init(element, opts)
        : new Flipsnap(element, opts);
    }
    
    Flipsnap.prototype.init = function(element, opts) {
      var self = this;
    
      // set element
      self.element = element;
      if (typeof element === 'string') {
        self.element = document.querySelector(element);
      }
    
      if (!self.element) {
        throw new Error('element not found');
      }
    
      if (support.mspointer) {
        self.element.style.msTouchAction = 'pan-y';
      }
    
      // set opts
      opts = opts || {};
      self.distance = opts.distance;
      self.maxPoint = opts.maxPoint;
      self.disableTouch = (opts.disableTouch === undefined) ? false : opts.disableTouch;
      self.disable3d = (opts.disable3d === undefined) ? false : opts.disable3d;
      self.transitionDuration = (opts.transitionDuration === undefined) ? '350ms' : opts.transitionDuration + 'ms';
    
      // set property
      self.currentPoint = 0;
      self.currentX = 0;
      self.animation = false;
      self.use3d = support.transform3d;
      if (self.disable3d === true) {
        self.use3d = false;
      }
    
      // set default style
      if (support.cssAnimation) {
        self._setStyle({
          transitionProperty: getCSSVal('transform'),
          transitionTimingFunction: 'cubic-bezier(0,0,0.25,1)',
          transitionDuration: '0ms',
          transform: self._getTranslate(0)
        });
      }
      else {
        self._setStyle({
          position: 'relative',
          left: '0px'
        });
      }
    
      // initilize
      self.refresh();
    
      eventTypes.forEach(function(type) {
        self.element.addEventListener(events.start[type], self, false);
      });
    
      return self;
    };
    
    Flipsnap.prototype.handleEvent = function(event) {
      var self = this;
    
      switch (event.type) {
        // start
        case events.start.touch: self._touchStart(event, 'touch'); break;
        case events.start.mouse: self._touchStart(event, 'mouse'); break;
    
        // move
        case events.move.touch: self._touchMove(event, 'touch'); break;
        case events.move.mouse: self._touchMove(event, 'mouse'); break;
    
        // end
        case events.end.touch: self._touchEnd(event, 'touch'); break;
        case events.end.mouse: self._touchEnd(event, 'mouse'); break;
    
        // click
        case 'click': self._click(event); break;
      }
    };
    
    Flipsnap.prototype.refresh = function() {
      var self = this;
    
      // setting max point
      self._maxPoint = (self.maxPoint === undefined) ? (function() {
        var childNodes = self.element.childNodes,
          itemLength = -1,
          i = 0,
          len = childNodes.length,
          node;
        for(; i < len; i++) {
          node = childNodes[i];
          if (node.nodeType === 1) {
            itemLength++;
          }
        }
    
        return itemLength;
      })() : self.maxPoint;
    
      // setting distance
      if (self.distance === undefined) {
        if (self._maxPoint < 0) {
          self._distance = 0;
        }
        else {
          self._distance = self.element.scrollWidth / (self._maxPoint + 1);
        }
      }
      else {
        self._distance = self.distance;
      }
    
      // setting maxX
      self._maxX = -self._distance * self._maxPoint;
    
      self.moveToPoint();
    };
    
    Flipsnap.prototype.hasNext = function() {
      var self = this;
    
      return self.currentPoint < self._maxPoint;
    };
    
    Flipsnap.prototype.hasPrev = function() {
      var self = this;
    
      return self.currentPoint > 0;
    };
    
    Flipsnap.prototype.toNext = function(transitionDuration) {
      var self = this;
    
      if (!self.hasNext()) {
        return;
      }
    
      self.moveToPoint(self.currentPoint + 1, transitionDuration);
    };
    
    Flipsnap.prototype.toPrev = function(transitionDuration) {
      var self = this;
    
      if (!self.hasPrev()) {
        return;
      }
    
      self.moveToPoint(self.currentPoint - 1, transitionDuration);
    };
    
    Flipsnap.prototype.moveToPoint = function(point, transitionDuration) {
      var self = this;
      
      transitionDuration = transitionDuration === undefined
        ? self.transitionDuration : transitionDuration + 'ms';
    
      var beforePoint = self.currentPoint;
    
      // not called from `refresh()`
      if (point === undefined) {
        point = self.currentPoint;
      }
    
      if (point < 0) {
        self.currentPoint = 0;
      }
      else if (point > self._maxPoint) {
        self.currentPoint = self._maxPoint;
      }
      else {
        self.currentPoint = parseInt(point, 10);
      }
    
      if (support.cssAnimation) {
        self._setStyle({ transitionDuration: transitionDuration });
      }
      else {
        self.animation = true;
      }
      self._setX(- self.currentPoint * self._distance, transitionDuration);
    
      if (beforePoint !== self.currentPoint) { // is move?
        // `fsmoveend` is deprecated
        // `fspointmove` is recommend.
        self._triggerEvent('fsmoveend', true, false);
        self._triggerEvent('fspointmove', true, false);
      }
    };
    
    Flipsnap.prototype._setX = function(x, transitionDuration) {
      var self = this;
    
      self.currentX = x;
      if (support.cssAnimation) {
        self.element.style[ saveProp.transform ] = self._getTranslate(x);
      }
      else {
        if (self.animation) {
          self._animate(x, transitionDuration || self.transitionDuration);
        }
        else {
          self.element.style.left = x + 'px';
        }
      }
    };
    
    Flipsnap.prototype._touchStart = function(event, type) {
      var self = this;
    
      if (self.disableTouch || self.scrolling || gestureStart) {
        return;
      }
    
      self.element.addEventListener(events.move[type], self, false);
      document.addEventListener(events.end[type], self, false);
    
      var tagName = event.target.tagName;
      if (type === 'mouse' && tagName !== 'SELECT' && tagName !== 'INPUT' && tagName !== 'TEXTAREA' && tagName !== 'BUTTON') {
        event.preventDefault();
      }
    
      if (support.cssAnimation) {
        self._setStyle({ transitionDuration: '0ms' });
      }
      else {
        self.animation = false;
      }
      self.scrolling = true;
      self.moveReady = false;
      self.startPageX = getPage(event, 'pageX');
      self.startPageY = getPage(event, 'pageY');
      self.basePageX = self.startPageX;
      self.directionX = 0;
      self.startTime = event.timeStamp;
      self._triggerEvent('fstouchstart', true, false);
    };
    
    Flipsnap.prototype._touchMove = function(event, type) {
      var self = this;
    
      if (!self.scrolling || gestureStart) {
        return;
      }
    
      var pageX = getPage(event, 'pageX');
      var pageY = getPage(event, 'pageY');
      var distX;
      var newX;
    
      if (self.moveReady) {
        event.preventDefault();
    
        distX = pageX - self.basePageX;
        newX = self.currentX + distX;
        if (newX >= 0 || newX < self._maxX) {
          newX = Math.round(self.currentX + distX / 3);
        }
    
        // When distX is 0, use one previous value.
        // For android firefox. When touchend fired, touchmove also
        // fired and distX is certainly set to 0. 
        self.directionX =
          distX === 0 ? self.directionX :
          distX > 0 ? -1 : 1;
    
        // if they prevent us then stop it
        var isPrevent = !self._triggerEvent('fstouchmove', true, true, {
          delta: distX,
          direction: self.directionX
        });
    
        if (isPrevent) {
          self._touchAfter({
            moved: false,
            originalPoint: self.currentPoint,
            newPoint: self.currentPoint,
            cancelled: true
          });
        } else {
          self._setX(newX);
        }
      }
      else {
        // https://github.com/hokaccha/js-flipsnap/pull/36
        var triangle = getTriangleSide(self.startPageX, self.startPageY, pageX, pageY);
        if (triangle.z > DISTANCE_THRESHOLD) {
          if (getAngle(triangle) > ANGLE_THREHOLD) {
            event.preventDefault();
            self.moveReady = true;
            self.element.addEventListener('click', self, true);
          }
          else {
            self.scrolling = false;
          }
        }
      }
    
      self.basePageX = pageX;
    };
    
    Flipsnap.prototype._touchEnd = function(event, type) {
      var self = this;
    
      self.element.removeEventListener(events.move[type], self, false);
      document.removeEventListener(events.end[type], self, false);
    
      if (!self.scrolling) {
        return;
      }
    
      var newPoint = -self.currentX / self._distance;
      newPoint =
        (self.directionX > 0) ? Math.ceil(newPoint) :
        (self.directionX < 0) ? Math.floor(newPoint) :
        Math.round(newPoint);
    
      if (newPoint < 0) {
        newPoint = 0;
      }
      else if (newPoint > self._maxPoint) {
        newPoint = self._maxPoint;
      }
    
      self._touchAfter({
        moved: newPoint !== self.currentPoint,
        originalPoint: self.currentPoint,
        newPoint: newPoint,
        cancelled: false
      });
    
      self.moveToPoint(newPoint);
    };
    
    Flipsnap.prototype._click = function(event) {
      var self = this;
    
      event.stopPropagation();
      event.preventDefault();
    };
    
    Flipsnap.prototype._touchAfter = function(params) {
      var self = this;
    
      self.scrolling = false;
      self.moveReady = false;
    
      setTimeout(function() {
        self.element.removeEventListener('click', self, true);
      }, 200);
    
      self._triggerEvent('fstouchend', true, false, params);
    };
    
    Flipsnap.prototype._setStyle = function(styles) {
      var self = this;
      var style = self.element.style;
    
      for (var prop in styles) {
        setStyle(style, prop, styles[prop]);
      }
    };
    
    Flipsnap.prototype._animate = function(x, transitionDuration) {
      var self = this;
    
      var elem = self.element;
      var begin = +new Date();
      var from = parseInt(elem.style.left, 10);
      var to = x;
      var duration = parseInt(transitionDuration, 10);
      var easing = function(time, duration) {
        return -(time /= duration) * (time - 2);
      };
      var timer = setInterval(function() {
        var time = new Date() - begin;
        var pos, now;
        if (time > duration) {
          clearInterval(timer);
          now = to;
        }
        else {
          pos = easing(time, duration);
          now = pos * (to - from) + from;
        }
        elem.style.left = now + "px";
      }, 10);
    };
    
    Flipsnap.prototype.destroy = function() {
      var self = this;
    
      eventTypes.forEach(function(type) {
        self.element.removeEventListener(events.start[type], self, false);
      });
    };
    
    Flipsnap.prototype._getTranslate = function(x) {
      var self = this;
    
      return self.use3d
        ? 'translate3d(' + x + 'px, 0, 0)'
        : 'translate(' + x + 'px, 0)';
    };
    
    Flipsnap.prototype._triggerEvent = function(type, bubbles, cancelable, data) {
      var self = this;
    
      var ev = document.createEvent('Event');
      ev.initEvent(type, bubbles, cancelable);
    
      if (data) {
        for (var d in data) {
          if (data.hasOwnProperty(d)) {
            ev[d] = data[d];
          }
        }
      }
    
      return self.element.dispatchEvent(ev);
    };
    
    function getPage(event, page) {
      return event.changedTouches ? event.changedTouches[0][page] : event[page];
    }
    
    function hasProp(props) {
      return some(props, function(prop) {
        return div.style[ prop ] !== undefined;
      });
    }
    
    function setStyle(style, prop, val) {
      var _saveProp = saveProp[ prop ];
      if (_saveProp) {
        style[ _saveProp ] = val;
      }
      else if (style[ prop ] !== undefined) {
        saveProp[ prop ] = prop;
        style[ prop ] = val;
      }
      else {
        some(prefix, function(_prefix) {
          var _prop = ucFirst(_prefix) + ucFirst(prop);
          if (style[ _prop ] !== undefined) {
            saveProp[ prop ] = _prop;
            style[ _prop ] = val;
            return true;
          }
        });
      }
    }
    
    function getCSSVal(prop) {
      if (div.style[ prop ] !== undefined) {
        return prop;
      }
      else {
        var ret;
        some(prefix, function(_prefix) {
          var _prop = ucFirst(_prefix) + ucFirst(prop);
          if (div.style[ _prop ] !== undefined) {
            ret = '-' + _prefix + '-' + prop;
            return true;
          }
        });
        return ret;
      }
    }
    
    function ucFirst(str) {
      return str.charAt(0).toUpperCase() + str.substr(1);
    }
    
    function some(ary, callback) {
      for (var i = 0, len = ary.length; i < len; i++) {
        if (callback(ary[i], i)) {
          return true;
        }
      }
      return false;
    }
    
    function getTriangleSide(x1, y1, x2, y2) {
      var x = Math.abs(x1 - x2);
      var y = Math.abs(y1 - y2);
      var z = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
    
      return {
        x: x,
        y: y,
        z: z
      };
    }
    
    function getAngle(triangle) {
      var cos = triangle.y / triangle.z;
      var radina = Math.acos(cos);
    
      return 180 / (Math.PI / radina);
    }
    
    if (typeof exports == 'object') {
      module.exports = Flipsnap;
    }
    else if (typeof define == 'function' && define.amd) {
      define(function() {
        return Flipsnap;
      });
    }
    else {
      window.Flipsnap = Flipsnap;
    }
    
    })(window, window.document);
    

      

  • 相关阅读:
    线程TLAB区域的深入剖析
    ivotal-tc-Server与Tomcat区别
    Java线程面试题 Top 50 (转载)
    Java并发编程:Timer和TimerTask(转载)
    Java并发编程:Callable、Future和FutureTask
    Java并发编程:CountDownLatch、CyclicBarrier和Semaphore
    Java并发编程:线程池的使用
    Java多线程与并发库高级应用-可阻塞的队列
    java多线程与并发库高级应用-工具类介绍
    Google guava工具类的介绍和使用
  • 原文地址:https://www.cnblogs.com/surfaces/p/4552588.html
Copyright © 2011-2022 走看看