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);

  

你可能感兴趣的:(js)