APICloud开发者进阶之路|[ 新手教程 ] 原生js 会话列表滑动删除置顶效果

完整地址:https://community.apicloud.co...

`/! JRoll v2.6.1 ~ (c) 2015-2017 Author:BarZu Git:https://github.com/chjtx/JRoll Website:http://www.chjtx.com/JRoll/ /
/ global define, HTMLElement /
(function (window, document, Math) {
'use strict'

var JRoll
var VERSION = '2.6.1'
var rAF = window.requestAnimationFrame || window.webkitRequestAnimationFrame || function (callback) {

setTimeout(callback, 17)

}
var sty = document.createElement('div').style
var jrollMap = {} // 保存所有JRoll对象
var ua = navigator.userAgent.toLowerCase()
var prefix = (function () {

var vendors = ['OT', 'msT', 'MozT', 'webkitT', 't']
var transform
var i = vendors.length

while (i--) {
  transform = vendors[i] + 'ransform'
  if (transform in sty) return vendors[i]
}

})()

// 实用工具
var utils = {

// 兼容
TSF: prefix + 'ransform',
TSD: prefix + 'ransitionDuration',
TFO: prefix + 'ransformOrigin',
isAndroid: /android/.test(ua),
isIOS: /iphone|ipad/.test(ua),
isMobile: /mobile|phone|android|pad/.test(ua),

// 判断浏览是否支持perspective属性,从而判断是否支持开启3D加速
translateZ: (function (pre) {
  var f
  if (pre) {
    f = pre + 'Perspective' in sty
  } else {
    f = 'perspective' in sty
  }
  return f ? ' translateZ(0px)' : ''
})(prefix.substr(0, prefix.length - 1)),

// 计算相对偏移,a相对于b的偏移
computeTranslate: function (a, b) {
  var x = 0
  var y = 0
  var s
  while (a) {
    s = window.getComputedStyle(a)[utils.TSF].replace(/matrix\(|\)/g, '').split(', ')
    x += parseInt(s[4]) || 0
    y += parseInt(s[5]) || 0
    a = a.parentElement
    if (a === b) {
      a = null
    }
  }
  return {
    x: x,
    y: y
  }
},

// 计算相对位置,a相对于b的位置
computePosition: function (a, b) {
  var left = 0
  var top = 0
  while (a) {
    left += a.offsetLeft
    top += a.offsetTop
    a = a.offsetParent
    if (a === b) {
      a = null
    }
  }
  return {
    left: left,
    top: top
  }
},

/**
 * 在指定时间内将指定元素从开始位置移到结束位置并执行回调方法
 * el 必须是dom元素,必填
 * x,y 结束位置,必填
 * duration 过渡时长,单位ms,可选
 * callback 回调方法,可选
 * context 上下文,可选
 */
moveTo: function (el, x, y, duration, callback, context) {
  var startX = 0
  var startY = 0
  var endX
  var endY
  var zoom = 1
  var stepX
  var stepY
  var d
  var result
  result = /translate\(([-\d.]+)px,\s+([-\d.]+)px\)\s+(?:translateZ\(0px\)\s+)?scale\(([\d.]+)\)/.exec(el.style[utils.TSF])
  if (result) {
    startX = Number(result[1])
    startY = Number(result[2])
    zoom = Number(result[3])
  }
  d = duration || 17
  stepX = (x - startX) / (d / 17)
  stepY = (y - startY) / (d / 17)
  endX = startX
  endY = startY

  function moving () {
    d = d - 17
    if (d < 17) {
      endX = x
      endY = y
    } else {
      endX = parseInt(endX + stepX, 10)
      endY = parseInt(endY + stepY, 10)
    }
    el.style[utils.TSF] = 'translate(' + endX + 'px, ' + endY + 'px)' + utils.translateZ + ' scale(' + zoom + ')'

    // 执行用户注册的滑动事件
    if (context) {
      context.x = endX
      context.y = endY
      context._execEvent('scroll')
      if (context.scrollBtnX) context._runScrollBarX()
      if (context.scrollBtnY) context._runScrollBarY()
    }

    if (d > 0 && !(endX === x && endY === y)) {
      rAF(moving)
    } else if (typeof callback === 'function') {
      callback()
    }
  }

  moving()
},

/**
 * 一层一层往上查找已实例化的jroll
 * el 目标元素
 * force 强制查找,忽略textarea
 */
findScroller: function (el, force) {
  var id
  // 遇到document或带垂直滚动条的textarea终止查找
  if (force || !(el.tagName === 'TEXTAREA' && el.scrollHeight > el.offsetHeight)) {
    while (el !== document) {
      id = el.getAttribute('jroll-id')
      if (id) {
        return jrollMap[id]
      }
      el = el.parentNode
    }
  }
  return null
},
// 一层一层往上查找所有已实例化的jroll
findAllJRolls: function (el, force) {
  var jrolls = []
  var id
  // 遇到document或带垂直滚动条的textarea终止查找
  if (force || !(el.tagName === 'TEXTAREA' && (el.scrollHeight > el.clientHeight) && (el.scrollTop > 0 && el.scrollTop < el.scrollHeight - el.clientHeight))) {
    while (el !== document) {
      id = el.getAttribute('jroll-id')
      if (id) {
        jrolls.push(jrollMap[id])
      }
      el = el.parentNode
    }
  }
  return jrolls
}

}

function _touchstart (e) {

var jrolls = utils.findAllJRolls(e.target)
var l = jrolls.length

// 非缩放且第二个手指按屏中止往后执行
if (JRoll.jrollActive && !JRoll.jrollActive.options.zoom && e.touches && e.touches.length > 1) {
  return
}
if (l) {
  while (l--) {
    if (jrolls[l].moving) {
      e.preventDefault() // 防止按停滑动时误触a链接
      jrolls[l]._endAction() // 结束并终止惯性
    }
  }

  JRoll.jrollActive = jrolls[0]
  JRoll.jrollActive._start(e)
} else if (JRoll.jrollActive) {
  JRoll.jrollActive._end(e)
}

}

function _touchmove (e) {

if (JRoll.jrollActive) {
  var activeElement = document.activeElement
  if (JRoll.jrollActive.options.preventDefault) {
    e.preventDefault()
  }
  if (utils.isMobile && JRoll.jrollActive.options.autoBlur && (activeElement.tagName === 'INPUT' || activeElement.tagName === 'TEXTAREA')) {
    activeElement.blur()
  }
  JRoll.jrollActive._move(e)
}

}

function _touchend (e) {

if (JRoll.jrollActive) {
  JRoll.jrollActive._end(e)
}

}

function _resize () {

setTimeout(function () {
  for (var i in jrollMap) {
    jrollMap[i].refresh().scrollTo(jrollMap[i].x, jrollMap[i].y, 200)
  }
}, 600)

}

function _wheel (e) {

var jroll = utils.findScroller(e.target)
if (jroll) {
  jroll._wheel(e)
}

}

// 检测是否支持passive选项
var supportsPassiveOption = false
try {

var opts = Object.defineProperty({}, 'passive', {
  get: function () {
    supportsPassiveOption = true
  }
})
window.addEventListener('test', null, opts)

} catch (e) {}

function addEvent (type, method) {

document.addEventListener(type, method, supportsPassiveOption ? { passive: false } : false)

}

// 添加监听事件
addEvent(utils.isMobile ? 'touchstart' : 'mousedown', _touchstart)
addEvent(utils.isMobile ? 'touchmove' : 'mousemove', _touchmove)
addEvent(utils.isMobile ? 'touchend' : 'mouseup', _touchend)
if (utils.isMobile) {

addEvent('touchcancel', _touchend)

} else {

addEvent(/firefox/.test(ua) ? 'DOMMouseScroll' : 'mousewheel', _wheel)

}
window.addEventListener('resize', _resize)
window.addEventListener('orientationchange', _resize)

JRoll = function (el, options) {

var me = this

me.wrapper = typeof el === 'string' ? document.querySelector(el) : el
me.scroller = options && options.scroller ? (typeof options.scroller === 'string' ? document.querySelector(options.scroller) : options.scroller) : me.wrapper.children[0]

// 防止重复多次new JRoll
if (me.scroller.jroll) {
  me.scroller.jroll.refresh()
  return me.scroller.jroll
} else {
  me.scroller.jroll = me
}

this._init(el, options)

}

JRoll.version = VERSION

JRoll.utils = utils

JRoll.jrollMap = jrollMap

JRoll.prototype = {

// 初始化
_init: function (el, options) {
  var me = this

  // 计算wrapper相对document的位置
  me.wrapperOffset = utils.computePosition(me.wrapper, document.body)

  // 创建ID
  me.id = (options && options.id) || me.scroller.getAttribute('jroll-id') || 'jroll_' + Math.random().toString().substr(2, 8)

  // 保存jroll对象
  me.scroller.setAttribute('jroll-id', me.id)
  jrollMap[me.id] = me

  // 默认选项
  me.options = {
    scrollX: false,
    scrollY: true,
    scrollFree: false, // 自由滑动
    minX: null, // 向左滑动的边界值,默认为0
    maxX: null, // 向右滑动的边界值,默认为scroller的宽*-1
    minY: null, // 向下滑动的边界值,默认为0
    maxY: null, // 向上滑动的边界值,默认为scroller的高*-1
    zoom: false, // 使能缩放
    zoomMin: 1, // 最小缩放倍数
    zoomMax: 4, // 最大缩放倍数
    zoomDuration: 400, // 缩放结束后回到限定位置的过渡时间
    bounce: true, // 回弹
    scrollBarX: false, // 开启x滚动条
    scrollBarY: false, // 开启y滚动条
    scrollBarFade: false, // 滚动条使用渐隐模式
    preventDefault: true, // 禁止touchmove默认事件
    momentum: true, // 滑动结束平滑过渡
    autoStyle: true, // 自动为wrapper和scroller添加样式
    autoBlur: true,  // 在滑动时自动将input/textarea失焦
    edgeRelease: true // 边缘释放,滑动到上下边界自动结束,解决手指滑出屏幕没触发touchEnd事件的问题
  }

  for (var i in options) {
    if (i !== 'scroller') {
      me.options[i] = options[i]
    }
  }

  if (me.options.autoStyle) {
    // 将wrapper设为relative
    if (window.getComputedStyle(me.wrapper).position === 'static') {
      me.wrapper.style.position = 'relative'
      me.wrapper.style.top = '0'
      me.wrapper.style.left = '0'
    }
    me.wrapper.style.overflow = 'hidden'
    me.scroller.style.minHeight = '100%'
  }

  if (me.options.zoom) {
    // 该属性是为了解决缩放时与浏览器手势冲突造成缩放卡顿的问题,尤其是微信端
    // 设置该属性会导致 preventDefault 选项失效
    me.scroller.style.touchAction = 'none'
  }

  me.x = 0
  me.y = 0

  /**
   * 当前状态,可取值:
   * null
   * preScroll(准备滑动)
   * preZoom(准备缩放)
   * scrollX(横向)
   * scrollY(竖向)
   * scrollFree(各个方向)
   */
  me.s = null
  me.scrollBarX = null // x滚动条
  me.scrollBarY = null // y滚动条

  me._s = {
    startX: 0,
    startY: 0,
    lastX: 0,
    lastY: 0,
    endX: 0,
    endY: 0
  }

  me._z = {
    spacing: 0, // 两指间间距
    scale: 1,
    startScale: 1
  }

  me._event = {
    'scrollStart': [],
    'scroll': [],
    'scrollEnd': [],
    'zoomStart': [],
    'zoom': [],
    'zoomEnd': [],
    'refresh': [],
    'touchEnd': []
  }

  me.refresh(true)
},

// 开启
enable: function () {
  var me = this
  me.scroller.setAttribute('jroll-id', me.id)
  return me
},

// 关闭
disable: function () {
  var me = this
  me.scroller.removeAttribute('jroll-id')
  return me
},

// 销毁
destroy: function () {
  var me = this
  delete jrollMap[me.id]
  delete me.scroller.jroll
  if (me.scrollBarX) {
    me.wrapper.removeChild(me.scrollBarX)
  }
  if (me.scrollBarY) {
    me.wrapper.removeChild(me.scrollBarY)
  }
  me.disable()
  me.scroller.style[utils.TSF] = ''
  me.scroller.style[utils.TSD] = ''
  me.scroller.style[utils.TFO] = ''
  me.prototype = null
  for (var i in me) {
    if (me.hasOwnProperty(i)) {
      delete me[i]
    }
  }
},

// 替换对象
call: function (target, e) {
  var me = this
  me.scrollTo(me.x, me.y)
  JRoll.jrollActive = target
  if (e) target._start(e)
  return target
},

// 刷新JRoll的宽高
refresh: function (notRefreshEvent) {
  var me = this
  var wrapperStyle = window.getComputedStyle(me.wrapper)
  var scrollerStyle = window.getComputedStyle(me.scroller)
  var paddingX
  var paddingY
  var marginX
  var marginY
  var temp
  var size

  me.wrapperWidth = me.wrapper.clientWidth
  me.wrapperHeight = me.wrapper.clientHeight

  me.scrollerWidth = Math.round(me.scroller.offsetWidth * me._z.scale)
  me.scrollerHeight = Math.round(me.scroller.offsetHeight * me._z.scale)

  // 解决wrapper的padding和scroller的margin造成maxWidth/maxHeight计算错误的问题
  paddingX = parseInt(wrapperStyle['padding-left']) + parseInt(wrapperStyle['padding-right'])
  paddingY = parseInt(wrapperStyle['padding-top']) + parseInt(wrapperStyle['padding-bottom'])
  marginX = parseInt(scrollerStyle['margin-left']) + parseInt(scrollerStyle['margin-right'])
  marginY = parseInt(scrollerStyle['margin-top']) + parseInt(scrollerStyle['margin-bottom'])

  // 最大/最小范围
  me.minScrollX = me.options.minX === null ? 0 : me.options.minX
  me.maxScrollX = me.options.maxX === null ? me.wrapperWidth - me.scrollerWidth - paddingX - marginX : me.options.maxX
  me.minScrollY = me.options.minY === null ? 0 : me.options.minY
  me.maxScrollY = me.options.maxY === null ? me.wrapperHeight - me.scrollerHeight - paddingY - marginY : me.options.maxY

  if (me.minScrollX < 0) {
    me.minScrollX = 0
  }
  if (me.minScrollY < 0) {
    me.minScrollY = 0
  }
  if (me.maxScrollX > 0) {
    me.maxScrollX = 0
  }
  if (me.maxScrollY > 0) {
    me.maxScrollY = 0
  }

  me._s.endX = me.x
  me._s.endY = me.y

  // x滚动条
  if (me.options.scrollBarX) {
    if (!me.scrollBarX) {
      temp = me._createScrollBar('jroll-xbar', 'jroll-xbtn', false)
      me.scrollBarX = temp[0]
      me.scrollBtnX = temp[1]
    }
    me.scrollBarScaleX = me.wrapper.clientWidth / me.scrollerWidth
    size = Math.round(me.scrollBarX.clientWidth * me.scrollBarScaleX)
    me.scrollBtnX.style.width = (size > 8 ? size : 8) + 'px'
    me._runScrollBarX()
  } else if (me.scrollBarX) {
    me.wrapper.removeChild(me.scrollBarX)
    me.scrollBarX = null
  }
  // y滚动条
  if (me.options.scrollBarY) {
    if (!me.scrollBarY) {
      temp = me._createScrollBar('jroll-ybar', 'jroll-ybtn', true)
      me.scrollBarY = temp[0]
      me.scrollBtnY = temp[1]
    }
    me.scrollBarScaleY = me.wrapper.clientHeight / me.scrollerHeight
    size = Math.round(me.scrollBarY.clientHeight * me.scrollBarScaleY)
    me.scrollBtnY.style.height = (size > 8 ? size : 8) + 'px'
    me._runScrollBarY()
  } else if (me.scrollBarY) {
    me.wrapper.removeChild(me.scrollBarY)
    me.scrollBarY = null
  }

  if (!notRefreshEvent) {
    me._execEvent('refresh')
  }

  return me
},

scale: function (multiple) {
  var me = this
  var z = parseFloat(multiple)
  if (!isNaN(z)) {
    me.scroller.style[utils.TFO] = '0 0'
    me._z.scale = z
    me.refresh()._scrollTo(me.x, me.y)
    me.scrollTo(me.x, me.y, 400)
  }
  return me
},

_wheel: function (e) {
  var me = this
  var y = e.wheelDelta || -(e.detail / 3) * 120 // 兼容火狐
  if (me.options.scrollY || me.options.scrollFree) {
    me.scrollTo(me.x, me._compute(me.y + y, me.minScrollY, me.maxScrollY))
  }
},

// 滑动滚动条
_runScrollBarX: function () {
  var me = this
  var x = Math.round(-1 * me.x * me.scrollBarScaleX)

  me._scrollTo.call({
    scroller: me.scrollBtnX,
    _z: {
      scale: 1
    }
  }, x, 0)
},
_runScrollBarY: function () {
  var me = this
  var y = Math.round(-1 * me.y * me.scrollBarScaleY)

  me._scrollTo.call({
    scroller: me.scrollBtnY,
    _z: {
      scale: 1
    }
  }, 0, y)
},

// 创建滚动条
_createScrollBar: function (a, b, isY) {
  var me = this
  var bar
  var btn

  bar = document.createElement('div')
  btn = document.createElement('div')
  bar.className = a
  btn.className = b

  if (this.options.scrollBarX === true || this.options.scrollBarY === true) {
    if (isY) {
      bar.style.cssText = 'position:absolute;top:2px;right:2px;bottom:2px;width:6px;overflow:hidden;border-radius:2px;-webkit-transform: scaleX(.5);transform: scaleX(.5);'
      btn.style.cssText = 'background:rgba(0,0,0,.4);position:absolute;top:0;left:0;right:0;border-radius:2px;'
    } else {
      bar.style.cssText = 'position:absolute;left:2px;bottom:2px;right:2px;height:6px;overflow:hidden;border-radius:2px;-webkit-transform: scaleY(.5);transform: scaleY(.5);'
      btn.style.cssText = 'background:rgba(0,0,0,.4);height:100%;position:absolute;left:0;top:0;bottom:0;border-radius:2px;'
    }
  }

  if (me.options.scrollBarFade) {
    bar.style.opacity = 0
  }

  bar.appendChild(btn)
  me.wrapper.appendChild(bar)

  return [bar, btn]
},

// 滚动条渐隐
_fade: function (bar, time) {
  var me = this
  if (me.fading && time > 0) {
    time = time - 25
    if (time % 100 === 0) bar.style.opacity = time / 1000
  } else {
    return
  }
  rAF(me._fade.bind(me, bar, time))
},

on: function (event, callback) {
  var me = this
  switch (event) {
    case 'scrollStart':
      me._event.scrollStart.push(callback)
      break
    case 'scroll':
      me._event.scroll.push(callback)
      break
    case 'scrollEnd':
      me._event.scrollEnd.push(callback)
      break
    case 'zoomStart':
      me._event.zoomStart.push(callback)
      break
    case 'zoom':
      me._event.zoom.push(callback)
      break
    case 'zoomEnd':
      me._event.zoomEnd.push(callback)
      break
    case 'refresh':
      me._event.refresh.push(callback)
      break
    case 'touchEnd':
      me._event.touchEnd.push(callback)
      break
  }
  return me
},

_execEvent: function (event, e) {
  var me = this
  var i = me._event[event].length - 1
  for (; i >= 0; i--) {
    me._event[event][i].call(me, e)
  }
},

// 计算x,y的值
_compute: function (val, min, max) {
  var me = this
  if (val > min) {
    if (me.options.bounce && (val > (min + 10))) {
      return Math.round(min + ((val - min) / 4))
    } else {
      return min
    }
  }

  if (val < max) {
    if (me.options.bounce && (val < (max - 10))) {
      return Math.round(max + ((val - max) / 4))
    } else {
      return max
    }
  }

  return val
},

_scrollTo: function (x, y) {
  this.scroller.style[utils.TSF] = 'translate(' + x + 'px, ' + y + 'px)' + utils.translateZ + ' scale(' + this._z.scale + ')'
},

/**
 * 供用户调用的scrollTo方法
 * x x坐标
 * y y坐标
 * timing 滑动时长,使用css3的transition-duration进行过渡
 * allow  是否允许超出边界,默认为undefined即不允许超出边界
 * system 为true时即是本程序自己调用,默认为undefined即非本程序调用
 */
scrollTo: function (x, y, timing, allow, callback, system, t) {
  var me = this
  if (!allow) {
    // x
    if (x >= me.minScrollX) {
      me.x = me.minScrollX

      // 滑到最大值时手指继续滑,重置开始、结束位置,优化体验
      if (t) {
        me._s.startX = t[0].pageX
        me._s.endX = me.minScrollX
      }
    } else if (x <= me.maxScrollX) {
      me.x = me.maxScrollX
      if (t) {
        me._s.startX = t[0].pageX
        me._s.endX = me.maxScrollX
      }
    } else {
      me.x = x
    }

    // y
    if (y >= me.minScrollY) {
      me.y = me.minScrollY
      if (t) {
        me._s.startY = t[0].pageY
        me._s.endY = me.minScrollY
      }
    } else if (y <= me.maxScrollY) {
      me.y = me.maxScrollY
      if (t) {
        me._s.startY = t[0].pageY
        me._s.endY = me.maxScrollY
      }
    } else {
      me.y = y
    }
  } else {
    me.x = x
    me.y = y
  }
  if (!system) {
    me._s.endX = me.x
    me._s.endY = me.y
  }
  if (timing) {
    utils.moveTo(me.scroller, me.x, me.y, timing, callback, system ? me : null)
  } else {
    me._scrollTo(me.x, me.y)
    if (system) {
      me._execEvent('scroll', t && t[0])
    }
    if (typeof callback === 'function') {
      callback()
    }
  }

  if (me.scrollBtnX) me._runScrollBarX()
  if (me.scrollBtnY) me._runScrollBarY()

  return me
},

scrollToElement: function (selector, timing, allow, callback) {
  var me = this
  var el = typeof selector === 'string' ? me.scroller.querySelector(selector) : selector
  if (el instanceof HTMLElement) {
    var p = utils.computePosition(el, me.scroller)
    var t = utils.computeTranslate(el, me.scroller)
    var x = -(p.left + t.x)
    var y = -(p.top + t.y)
    return me.scrollTo(x, y, timing, allow, callback)
  }
},

_endAction: function () {
  var me = this
  me._s.endX = me.x
  me._s.endY = me.y
  me.moving = false

  if (me.options.scrollBarFade && !me.fading) {
    me.fading = true // 标记渐隐滚动条
    if (me.scrollBarX) me._fade(me.scrollBarX, 2000)
    if (me.scrollBarY) me._fade(me.scrollBarY, 2000)
  }
  me._execEvent('scrollEnd')
},

_stepBounce: function (time, count) {
  var me = this
  var now = Date.now()
  var t = now - time
  var s = 0

  if (t > 0) {
    me.speed = me.speed - t * 0.008
    s = Math.round(me.speed * t * count * 0.005)
    if (me.speed <= 0 || s <= 0 || isNaN(s)) {
      me.bouncing = false
      me.scrollTo(me.x, me.y, 200, false, function () {
        me._endAction()
      }, true)
      return
    }

    if (me.s === 'scrollY' || me.s === 'scrollFree') {
      me.y = me.y + s * me.directionY
    }
    if (me.s === 'scrollX' || me.s === 'scrollFree') {
      me.x = me.x + s * me.directionX
    }
    me.scrollTo(me.x, me.y, 0, true, null, true)
    rAF(me._stepBounce.bind(me, now, count - 1))
  }
},

_x: function (p) {
  var me = this
  var n = me.directionX * p
  if (!isNaN(n)) {
    me.x = me.x + n
    // 达到边界终止惯性,执行回弹
    if (me.x >= me.minScrollX || me.x <= me.maxScrollX) {
      if (me.options.bounce) {
        me.bouncing = true // 标记回弹
      } else {
        me.moving = false
      }
    }
  }
},

_y: function (p) {
  var me = this
  var n = me.directionY * p
  if (!isNaN(n)) {
    me.y = me.y + n
    // 达到边界终止惯性,执行回弹
    if (me.y >= me.minScrollY || me.y <= me.maxScrollY) {
      if (me.options.bounce) {
        me.bouncing = true // 标记回弹
      } else {
        me.moving = false
      }
    }
  }
},

_xy: function (p) {
  var me = this
  var x = Math.round(me.cosX * p)
  var y = Math.round(me.cosY * p)
  if (!isNaN(x) && !isNaN(y)) {
    me.x = me.x + x
    me.y = me.y + y
    // 达到边界终止惯性,执行回弹
    if ((me.x >= me.minScrollX || me.x <= me.maxScrollX) && (me.y >= me.minScrollY || me.y <= me.maxScrollY)) {
      me.moving = false
    }
  }
},

_step: function (time) {
  var me = this
  var now = Date.now()
  var t = now - time
  var s = 0

  // fixed github issue #63
  if (!me.id) {
    return
  }
  // 惯性滑动结束,执行回弹
  if (me.bouncing) {
    rAF(me._stepBounce.bind(me, time, 20))
    return
  }

  // 终止
  if (!me.moving) {
    me._endAction()
    return
  }

  // 防止t为0滑动终止造成卡顿现象
  if (t > 0) {
    me.speed = me.speed - t * (me.speed > 1.2 ? 0.001 : (me.speed > 0.6 ? 0.0008 : 0.0006))
    s = Math.round(me.speed * t)
    if (me.speed <= 0 || s <= 0) {
      me._endAction()
      return
    }
    time = now

    // _do是可变方法,可为_x,_y或_xy,在判断方向时判断为何值,避免在次处进行过多的判断操作
    me._do(s)
    me.scrollTo(me.x, me.y, 0, me.options.bounce && !me.options.scrollFree, null, true)
  }

  rAF(me._step.bind(me, time))
},

_doScroll: function (d, e) {
  var me = this
  var pageY
  me.distance = d
  if (me.options.bounce) {
    me.x = me._compute(me.x, me.minScrollX, me.maxScrollX)
    me.y = me._compute(me.y, me.minScrollY, me.maxScrollY)
  }
  me.scrollTo(me.x, me.y, 0, me.options.bounce, null, true, (e.touches || [e]))

  // 解决垂直滑动超出屏幕边界时捕捉不到touchend事件无法执行结束方法的问题
  if (e && e.touches && me.options.edgeRelease) {
    pageY = e.touches[0].pageY
    if (pageY <= 10 || pageY >= window.innerHeight - 10) {
      me._end(e)
    }
  }
},

// 判断是滑动JRoll还是滑动Textarea(垂直方向)
_yTextarea: function (e) {
  var me = this
  var target = e.target
  if (target.tagName === 'TEXTAREA' && target.scrollHeight > target.clientHeight &&

    // textarea滑动条在顶部,向上滑动时将滑动权交给textarea
    ((target.scrollTop === 0 && me.directionY === -1) ||

    // textarea滑动条在底部,向下滑动时将滑动权交给textarea
    (target.scrollTop === target.scrollHeight - target.clientHeight && me.directionY === 1))) {
    me._end(e, true)
    return false
  }
  return true
},

_start: function (e) {
  var me = this
  var t = e.touches || [e]

  // 判断缩放
  if (me.options.zoom && t.length > 1) {
    me.s = 'preZoom'
    me.scroller.style[utils.TFO] = '0 0'

    var c1 = Math.abs(t[0].pageX - t[1].pageX)
    var c2 = Math.abs(t[0].pageY - t[1].pageY)

    me._z.spacing = Math.sqrt(c1 * c1 + c2 * c2)
    me._z.startScale = me._z.scale

    me.originX = (t[0].pageX - t[1].pageX) / 2 + t[1].pageX -
      (utils.computePosition(me.scroller, document.body).left +
      utils.computeTranslate(me.scroller, document.body).x)

    me.originY = (t[0].pageY - t[1].pageY) / 2 + t[1].pageY -
      (utils.computePosition(me.scroller, document.body).top +
      utils.computeTranslate(me.scroller, document.body).y)

    me._execEvent('zoomStart', e)
    return
  }

  if (me.options.scrollBarFade) {
    me.fading = false // 终止滑动条渐隐
    if (me.scrollBarX) me.scrollBarX.style.opacity = 1
    if (me.scrollBarY) me.scrollBarY.style.opacity = 1
  }

  // 任意方向滑动
  if (me.options.scrollFree) {
    me._do = me._xy
    me.s = 'scrollFree'

  // 允许xy两个方向滑动
  } else if (me.options.scrollX && me.options.scrollY) {
    me.s = 'preScroll'

  // 只允许y
  } else if (!me.options.scrollX && me.options.scrollY) {
    me._do = me._y
    me.s = 'scrollY'

  // 只允许x
  } else if (me.options.scrollX && !me.options.scrollY) {
    me._do = me._x
    me.s = 'scrollX'
  } else {
    me.s = null
    return
  }

  me.distance = 0
  me.lastMoveTime = me.startTime = Date.now()
  me._s.lastX = me.startPositionX = me._s.startX = t[0].pageX
  me._s.lastY = me.startPositionY = me._s.startY = t[0].pageY

  me._execEvent('scrollStart', e)
},

_move: function (e) {
  var me = this
  var t = e.touches || [e]
  var now
  var x
  var y
  var dx
  var dy
  var px
  var py
  var sqrtXY
  var directionX = 1
  var directionY = 1

  // 一个很奇怪的问题,在小米5默认浏览器上同时对x,y进行赋值流畅度会降低
  // 因此采取选择性赋值以保证单向运行较好的滑动体验
  if (me.s === 'preScroll' || me.s === 'scrollX' || me.s === 'scrollFree') {
    x = t[0].pageX
  }
  if (me.s === 'preScroll' || me.s === 'scrollY' || me.s === 'scrollFree') {
    y = t[0].pageY
  }

  dx = x - me._s.lastX
  dy = y - me._s.lastY

  me._s.lastX = x
  me._s.lastY = y

  directionX = dx >= 0 ? 1 : -1 // 手指滑动方向,1(向右) | -1(向左)
  directionY = dy >= 0 ? 1 : -1 // 手指滑动方向,1(向下) | -1(向上)

  now = Date.now()

  if (now - me.lastMoveTime > 200 || me.directionX !== directionX || me.directionY !== directionY) {
    me.startTime = now
    me.startPositionX = x
    me.startPositionY = y
    me.directionX = directionX
    me.directionY = directionY
  }

  me.lastMoveTime = now

  px = x - me.startPositionX
  py = y - me.startPositionY

  // 判断滑动方向
  if (me.s === 'preScroll') {
    // 判断为y方向,y方向滑动较常使用,因此优先判断
    if (Math.abs(y - me._s.startY) >= Math.abs(x - me._s.startX)) {
      me._do = me._y
      me.s = 'scrollY'
      return
    }

    // 判断为x方向
    if (Math.abs(y - me._s.startY) < Math.abs(x - me._s.startX)) {
      me._do = me._x
      me.s = 'scrollX'
      return
    }
  }

  // y方向滑动
  if (me.s === 'scrollY') {
    me.y = y - me._s.startY + me._s.endY
    if (me._yTextarea(e)) {
      me._doScroll(py, e)
    }
    return
  }

  // x方向滑动
  if (me.s === 'scrollX') {
    me.x = x - me._s.startX + me._s.endX
    me._doScroll(px, e)
    return
  }

  // 任意方向滑动
  if (me.s === 'scrollFree') {
    me.x = x - me._s.startX + me._s.endX
    me.y = y - me._s.startY + me._s.endY
    sqrtXY = Math.sqrt(px * px + py * py)
    me.cosX = px / sqrtXY
    me.cosY = py / sqrtXY
    me._doScroll(Math.sqrt(px * px + py * py), e)
    return
  }

  // 缩放
  if (me.s === 'preZoom') {
    var c1 = Math.abs(t[0].pageX - t[1].pageX)
    var c2 = Math.abs(t[0].pageY - t[1].pageY)
    var spacing = Math.sqrt(c1 * c1 + c2 * c2)
    var scale = spacing / me._z.spacing * me._z.startScale
    var lastScale

    if (scale < me.options.zoomMin) {
      scale = me.options.zoomMin
    } else if (scale > me.options.zoomMax) {
      scale = me.options.zoomMax
    }

    lastScale = scale / me._z.startScale

    me.x = Math.round(me.originX - me.originX * lastScale + me._s.endX)
    me.y = Math.round(me.originY - me.originY * lastScale + me._s.endY)
    me._z.scale = scale

    me._scrollTo(me.x, me.y)
    me._execEvent('zoom', e)

    return
  }
},

_end: function (e, manual) {
  var me = this
  var ex1
  var ex2
  var now = Date.now()
  var s1 = me.s === 'scrollY'
  var s2 = me.s === 'scrollX'
  var s3 = me.s === 'scrollFree'

  // 滑动结束
  if (s1 || s2 || s3) {
    // 禁止第二个手指滑动,只有一个手指时touchend事件的touches.length为0
    // manual参数用于判断是否手动执行_end方法,用于处理带滚动条的texearea
    if (e.touches && e.touches.length && !manual) {
      return
    }

    me._execEvent('touchEnd')
    JRoll.jrollActive = null
    me.duration = now - me.startTime

    ex1 = me.y > me.minScrollY || me.y < me.maxScrollY
    ex2 = me.x > me.minScrollX || me.x < me.maxScrollX

    // 超出边界回弹
    if ((s1 && ex1) || (s2 && ex2) || (s3 && (ex1 || ex2))) {
      me.scrollTo(me.x, me.y, 300)._endAction()

    // 惯性滑动
    } else if (me.options.momentum && me.duration < 200 && me.distance) {
      me.speed = Math.abs(me.distance / me.duration)
      me.speed = me.speed > 2 ? 2 : me.speed
      me.moving = true
      rAF(me._step.bind(me, now))
    } else {
      me._endAction()
    }
    return
  }

  // 缩放结束
  if (me.s === 'preZoom') {
    me._execEvent('touchEnd')
    JRoll.jrollActive = null

    if (me._z.scale > me.options.zoomMax) {
      me._z.scale = me.options.zoomMax
    } else if (me._z.scale < me.options.zoomMin) {
      me._z.scale = me.options.zoomMin
    }

    me.refresh()

    me.scrollTo(me.x, me.y, me.options.zoomDuration)

    me._execEvent('zoomEnd')

    return
  }
}

}

if (typeof module !== 'undefined' && module.exports) {

module.exports = JRoll

}
if (typeof define === 'function') {

define(function () {
  return JRoll
})

}

window.JRoll = JRoll
})(window, document, Math)
`

你可能感兴趣的:(java,android,ios,objective-c,小程序)