vue2.0自定義指令,用touch事件替換scroll事件

冰影浴火發表於2018-01-08
  • 首先取消了預設的scroll事件,然後根據滑動的距離計算scrollTop的大小,對於滑動速度過快的,使用定時器製作了一個減速運動,模擬手指離開螢幕時頁面繼續滑動的情況。
  • 使用這個指令要求繫結元素必須有高度

下面是程式碼

Vue.directive('touchMove', {
  inserted (el, binding, vnode) {
    if (el.style.height === 'auto') return // 當繫結元素height為auto時,直接返回
    let start, date, dateStart
    let scrollPrevious = 0 // 儲存滾動條上次所在位置
    let moveSave = []
    let dateSave = []
    let timmer = null
    let scrollNow = 0 // 滾動當前所在位置
    
    el.addEventListener('touchstart', function (e) {
      clearInterval(timmer)
      moveSave = []
      dateSave = []
      scrollPrevious = el.scrollTop
      start = e.targetTouches[0].clientY // 手指開始接觸螢幕時所在螢幕Y軸位置
      dateStart = new Date()
    })

    el.addEventListener('touchmove', function (e) {
      e.preventDefault()
      let move = e.targetTouches[0].clientY // 手指滑動時所在螢幕Y軸位置
      let distance = move - start // 每次滑動的距離
      let date = new Date()
      if (moveSave.length < 2) { 
        moveSave.push(move) // 儲存最近兩次滑動所在的位置跟時間
        dateSave.push(date)
      } else {
        moveSave.shift()
        moveSave.push(move)
        dateSave.shift()
        dateSave.push(date)
      }
      el.scrollTop = -distance + scrollPrevious
      if (moveSave[1] < moveSave[0]) {
        if (binding.value && binding.value.upScroll) {
          binding.value.upScroll(el, vnode) // 向上滑動時執行的函式
        }
      } else {
        if (binding.value && binding.value.downScroll) {
          binding.value.downScroll(el, vnode) // 向下滑動時執行的函式
        }
      }
    })

    el.addEventListener('touchend', function (e) {
      let speed = 0 // 滑動速度(單位px/ms)
      let elementHeight = el.scrollHeight - el.clientHeight // 滾動條最大值
      let reduction = 0.01 // 加速度
      if (moveSave.length < 2) {
        speed = (moveSave[0] - start) / (dateSave[0] - dateStart)
      } else {
        speed = (moveSave[1] - moveSave[0]) / (dateSave[1] - dateSave[0])
      }
      if (speed > 5) { // 限制speed的最大值跟最小值
        speed = 5
      }
      if (speed < -5) {
        speed = -5
      }
      if (Math.abs(speed) > .5) { // speed超過某一直後就會持續移動
        timmer = setInterval(function() {
          if (speed < 0) {
            speed = speed + reduction
            if (binding.value && binding.value.upScroll) {
              binding.value.upScroll(el) // 向上滑動時執行的函式
            }
            if (speed > 0) {
              speed = 0
            }
            scrollNow += -speed * 16
          } else if (speed > 0) {
            speed = speed - reduction
            if (binding.value && binding.value.downScroll) {
              binding.value.downScroll(el) // 向下滑動時執行的函式
            }
            if (speed < 0) {
              speed = 0
            }
            scrollNow -= speed * 16 
          }
          el.scrollTop = scrollNow
          if (speed === 0 || el.scrollTop === 0 || el.scrollTop === elementHeight) {
            clearInterval(timmer)
          }
        }, 16)
      }
    })
  }
})
複製程式碼

相關文章