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

    /*! 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;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)
    

      完整内容地址:https://community.apicloud.com/bbs/thread-87977-1-1.html

  • 相关阅读:
    中途接手一个项目时候,需要注意
    PPT做交互效果
    hyperledger学习资料
    k8s拾遗
    Day0-3. 部署docker镜像私有仓库harbor
    Day0-2. Docker安装部署
    Day0-1. Docker环境准备
    【转载】轻量级HTTP服务器Nginx(Nginx性能优化技巧)
    使用nginx-module-vts监控各虚拟主机的流量
    Linux系统下终端proxy代理配置
  • 原文地址:https://www.cnblogs.com/APICloud/p/12768730.html
Copyright © 2011-2022 走看看