'a'
mh-two-thousand-and-two
2024-04-12 44d2c92345cd156a59fc327b3060292a282d2893
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
const addListenerToElement = function (element, type, callback, capture) {
  // 暂时忽略 capture
  element.addEventListener(type, $event => {
    if (typeof callback === 'function') {
      if (callback($event) === false) {
        $event.preventDefault()
        $event.stopPropagation()
      }
    }
  }, {
    capture,
    passive: false
  })
}
 
export default {
  beforeDestroy () {
    document.removeEventListener('mousemove', this.__mouseMoveEventListener)
    document.removeEventListener('mouseup', this.__mouseUpEventListener)
  },
  methods: {
    touchtrack: function (element, method, useCancel) {
      const self = this
      let x0 = 0
      let y0 = 0
      let x1 = 0
      let y1 = 0
      const fn = function ($event, state, x, y) {
        if (self[method]({
          target: $event.target,
          currentTarget: $event.currentTarget,
          preventDefault: $event.preventDefault.bind($event),
          stopPropagation: $event.stopPropagation.bind($event),
          touches: $event.touches,
          changedTouches: $event.changedTouches,
          detail: {
            state,
            x: x,
            y: y,
            dx: x - x0,
            dy: y - y0,
            ddx: x - x1,
            ddy: y - y1,
            timeStamp: $event.timeStamp
          }
        }) === false) {
          return false
        }
      }
 
      let $eventOld = null
      let hasClickListenerOld
      let hasTouchStart
      let hasMouseDown
      addListenerToElement(element, 'touchstart', function ($event) {
        hasTouchStart = true
        if ($event.touches.length === 1 && !$eventOld) {
          $eventOld = $event
          x0 = x1 = $event.touches[0].pageX
          y0 = y1 = $event.touches[0].pageY
          return fn($event, 'start', x0, y0)
        }
      })
      addListenerToElement(element, 'mousedown', function ($event) {
        hasMouseDown = true
        if (!hasTouchStart && !$eventOld) {
          // TODO touches changedTouches
          $eventOld = $event
          x0 = x1 = $event.pageX
          y0 = y1 = $event.pageY
          return fn($event, 'start', x0, y0)
        }
      })
      addListenerToElement(element, 'touchmove', function ($event) {
        if ($event.touches.length === 1 && $eventOld) {
          const res = fn($event, 'move', $event.touches[0].pageX, $event.touches[0].pageY)
          x1 = $event.touches[0].pageX
          y1 = $event.touches[0].pageY
          return res
        }
      })
 
      // 阻止点击事件传播,处理拖拽和点击冲突,鼠标移动则添加监听,停止移动则移除监听
      const clickEventListener = this.__clickEventListener = function ($event) {
        $event.preventDefault()
        $event.stopPropagation()
      }
 
      const mouseMoveEventListener = this.__mouseMoveEventListener = function ($event) {
        if (!hasTouchStart && hasMouseDown && $eventOld) {
          // 存在鼠标移动,则在 document 上添加点击监听(好处是不用管具体使用拖拽的是什么元素)
          if (!hasClickListenerOld && (Math.abs(x1 - x0) > 2 || Math.abs(y1 - y0) > 2)) {
            document.addEventListener('click', clickEventListener, true)
            hasClickListenerOld = true
          }
          // TODO target currentTarget touches changedTouches
          const res = fn($event, 'move', $event.pageX, $event.pageY)
          x1 = $event.pageX
          y1 = $event.pageY
          return res
        }
      }
      document.addEventListener('mousemove', mouseMoveEventListener)
      addListenerToElement(element, 'touchend', function ($event) {
        if ($event.touches.length === 0 && $eventOld) {
          hasTouchStart = false
          $eventOld = null
          return fn($event, 'end', $event.changedTouches[0].pageX, $event.changedTouches[0].pageY)
        }
      })
      const mouseUpEventListener = this.__mouseUpEventListener = ($event) => {
        hasMouseDown = false
        if (!hasTouchStart && $eventOld) {
          // 鼠标抬起,存在监听,则 mouseup 结束后移除就监听事件
          if (hasClickListenerOld) {
            setTimeout(() => {
              document.removeEventListener('click', this.__clickEventListener, true)
              hasClickListenerOld = false
            }, 0)
          }
          // TODO target currentTarget touches changedTouches
          $eventOld = null
          return fn($event, 'end', $event.pageX, $event.pageY)
        }
      }
      document.addEventListener('mouseup', mouseUpEventListener)
 
      addListenerToElement(element, 'touchcancel', function ($event) {
        if ($eventOld) {
          hasTouchStart = false
          const $eventTemp = $eventOld
          $eventOld = null
          return fn($event, useCancel ? 'cancel' : 'end', $eventTemp.touches[0].pageX, $eventTemp.touches[0].pageY)
        }
      })
    }
  }
}