Skip to content

Commit c8f6006

Browse files
committed
feat(TouchSwipe): Highly improve TouchSwipe
1 parent 1fd7cea commit c8f6006

File tree

6 files changed

+127
-65
lines changed

6 files changed

+127
-65
lines changed

docs/src/examples/TouchSwipe/Basic.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<template>
22
<div class="q-pa-md row justify-center">
33
<q-card
4-
v-touch-swipe="handleSwipe"
4+
v-touch-swipe.mouse="handleSwipe"
55
class="custom-area cursor-pointer bg-primary text-white shadow-2 relative-position row flex-center"
66
>
77
<div v-if="info" class="custom-info">

docs/src/examples/TouchSwipe/Right.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<template>
22
<div class="q-pa-md row justify-center">
33
<q-card
4-
v-touch-swipe.right="handleSwipe"
4+
v-touch-swipe.mouse.right="handleSwipe"
55
class="custom-area cursor-pointer bg-primary text-white shadow-2 relative-position row flex-center"
66
>
77
<div v-if="info" class="custom-info">

docs/src/examples/TouchSwipe/UpOrLeft.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<template>
22
<div class="q-pa-md row justify-center">
33
<q-card
4-
v-touch-swipe.up.left="handleSwipe"
4+
v-touch-swipe.mouse.up.left="handleSwipe"
55
class="custom-area cursor-pointer bg-primary text-white shadow-2 relative-position row flex-center"
66
>
77
<div v-if="info" class="custom-info">

quasar/dev/components/touch-directives/touch-swipe.vue

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
on the area below to see it in action.
88
</p>
99
<div
10-
v-touch-swipe="handleSwipe"
10+
v-touch-swipe.mouse="handleSwipe"
11+
@click="onClick"
1112
class="custom-area row flex-center"
1213
>
1314
<div v-if="info" class="custom-info">
@@ -31,7 +32,8 @@
3132

3233
<p class="caption">Example on capturing only swipe to right:</p>
3334
<div
34-
v-touch-swipe.right="swipeToRight"
35+
v-touch-swipe.right.mouse="swipeToRight"
36+
@click="onClick"
3537
class="custom-area row flex-center"
3638
>
3739
<div v-if="infoRight" class="custom-info">
@@ -45,7 +47,8 @@
4547

4648
<p class="caption">Example on capturing only swipe up and right:</p>
4749
<div
48-
v-touch-swipe.up.right="swipeToCustom"
50+
v-touch-swipe.up.right.mouse="swipeToCustom"
51+
@click="onClick"
4952
class="custom-area row flex-center"
5053
>
5154
<div v-if="infoCustom" class="custom-info">
@@ -88,6 +91,9 @@ export default {
8891
},
8992
swipeToCustom ({ direction, duration, distance }) {
9093
this.infoCustom = { direction, duration, distance }
94+
},
95+
onClick () {
96+
console.log('onClick')
9197
}
9298
}
9399
}

quasar/src/directives/TouchSwipe.js

Lines changed: 110 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
import { position, leftClick } from '../utils/event.js'
1+
import Platform from '../plugins/Platform.js'
2+
import { position, leftClick, stopAndPrevent } from '../utils/event.js'
3+
import { clearSelection } from '../utils/selection.js'
24

35
function getDirection (mod) {
46
let dir = {}
@@ -31,15 +33,31 @@ function getDirection (mod) {
3133
return dir
3234
}
3335

36+
function parseArg (arg) {
37+
// delta (min velocity -- dist / time)
38+
// mobile min distance on first move
39+
// desktop min distance until deciding if it's a swipe or not
40+
const data = [0.06, 6, 50]
41+
42+
if (typeof arg === 'string' && arg.length) {
43+
arg.split(':').forEach((val, index) => {
44+
const v = parseInt(val, 10)
45+
v && (data[index] = v)
46+
})
47+
}
48+
49+
return data
50+
}
51+
3452
export default {
3553
name: 'touch-swipe',
3654

3755
bind (el, binding) {
38-
const mouse = binding.modifiers.noMouse !== true
56+
const mouse = binding.modifiers.mouse === true
3957

4058
let ctx = {
4159
handler: binding.value,
42-
threshold: parseInt(binding.arg, 10) || 300,
60+
sensitivity: parseArg(binding.arg),
4361
mod: binding.modifiers,
4462
direction: getDirection(binding.modifiers),
4563

@@ -50,38 +68,39 @@ export default {
5068
ctx.start(evt)
5169
}
5270
},
71+
5372
mouseEnd (evt) {
5473
document.removeEventListener('mousemove', ctx.move)
5574
document.removeEventListener('mouseup', ctx.mouseEnd)
5675
ctx.end(evt)
5776
},
5877

5978
start (evt) {
79+
console.log('start')
6080
const pos = position(evt)
6181

6282
ctx.event = {
6383
x: pos.left,
6484
y: pos.top,
6585
time: new Date().getTime(),
66-
detected: false,
86+
dir: false,
6787
abort: false
6888
}
69-
70-
el.classList.add('q-touch')
7189
},
90+
7291
move (evt) {
73-
if (ctx.event.abort) {
92+
if (ctx.event.abort === true) {
7493
return
7594
}
7695

77-
if (new Date().getTime() - ctx.event.time > ctx.threshold) {
78-
ctx.event.abort = true
96+
if (ctx.event.dir !== false) {
97+
stopAndPrevent(evt)
7998
return
8099
}
81100

82-
if (ctx.event.detected) {
83-
evt.stopPropagation()
84-
evt.preventDefault()
101+
const time = (new Date().getTime() - ctx.event.time)
102+
103+
if (time === 0) {
85104
return
86105
}
87106

@@ -92,68 +111,105 @@ export default {
92111
distY = pos.top - ctx.event.y,
93112
absY = Math.abs(distY)
94113

95-
if (absX === absY) {
114+
if (Platform.is.mobile) {
115+
if (absX < ctx.sensitivity[1] && absY < ctx.sensitivity[1]) {
116+
ctx.event.abort = true
117+
return
118+
}
119+
}
120+
else if (absX < ctx.sensitivity[2] && absY < ctx.sensitivity[2]) {
96121
return
97122
}
98123

99-
ctx.event.detected = true
100-
ctx.event.abort = !(
101-
(ctx.direction.vertical && absX < absY) ||
102-
(ctx.direction.horizontal && absX > absY) ||
103-
(ctx.direction.up && absX < absY && distY < 0) ||
104-
(ctx.direction.down && absX < absY && distY > 0) ||
105-
(ctx.direction.left && absX > absY && distX < 0) ||
106-
(ctx.direction.right && absX > absY && distX > 0)
107-
)
108-
109-
ctx.move(evt)
110-
},
111-
end (evt) {
112-
el.classList.remove('q-touch')
113-
if (ctx.event.abort || !ctx.event.detected) {
114-
return
124+
const
125+
velX = absX / time,
126+
velY = absY / time
127+
128+
if (
129+
ctx.direction.vertical &&
130+
absX < absY &&
131+
absX < 100 &&
132+
velY > ctx.sensitivity[0]
133+
) {
134+
ctx.event.dir = distY < 0 ? 'up' : 'down'
115135
}
116136

117-
const duration = new Date().getTime() - ctx.event.time
118-
if (duration > ctx.threshold) {
119-
return
137+
if (
138+
ctx.direction.horizontal &&
139+
absX > absY &&
140+
absY < 100 &&
141+
velX > ctx.sensitivity[0]
142+
) {
143+
ctx.event.dir = distX < 0 ? 'left' : 'right'
120144
}
121145

122-
evt.stopPropagation()
123-
evt.preventDefault()
146+
if (
147+
ctx.direction.up &&
148+
absX < absY &&
149+
distY < 0 &&
150+
absX < 100 &&
151+
velY > ctx.sensitivity[0]
152+
) {
153+
ctx.event.dir = 'up'
154+
}
124155

125-
let
126-
pos = position(evt),
127-
direction,
128-
distX = pos.left - ctx.event.x,
129-
absX = Math.abs(distX),
130-
distY = pos.top - ctx.event.y,
131-
absY = Math.abs(distY)
156+
if (
157+
ctx.direction.down &&
158+
absX < absY &&
159+
distY > 0 &&
160+
absX < 100 &&
161+
velY > ctx.sensitivity[0]
162+
) {
163+
ctx.event.dir = 'down'
164+
}
132165

133-
if (absX >= absY) {
134-
if (absX < 50) {
135-
return
136-
}
137-
direction = distX < 0 ? 'left' : 'right'
166+
if (
167+
ctx.direction.left &&
168+
absX > absY &&
169+
distX < 0 &&
170+
absY < 100 &&
171+
velX > ctx.sensitivity[0]
172+
) {
173+
ctx.event.dir = 'left'
138174
}
139-
else {
140-
if (absY < 50) {
141-
return
142-
}
143-
direction = distY < 0 ? 'up' : 'down'
175+
176+
if (
177+
ctx.direction.right &&
178+
absX > absY &&
179+
distX > 0 &&
180+
absY < 100 &&
181+
velX > ctx.sensitivity[0]
182+
) {
183+
ctx.event.dir = 'right'
144184
}
145185

146-
if (ctx.direction[direction]) {
186+
if (ctx.event.dir !== false) {
187+
stopAndPrevent(evt)
188+
document.body.classList.add('no-pointer-events')
189+
document.body.classList.add('non-selectable')
190+
clearSelection()
191+
147192
ctx.handler({
148193
evt,
149-
direction,
150-
duration,
194+
direction: ctx.event.dir,
195+
duration: time,
151196
distance: {
152197
x: absX,
153198
y: absY
154199
}
155200
})
156201
}
202+
else {
203+
ctx.event.abort = true
204+
}
205+
},
206+
207+
end (evt) {
208+
if (ctx.event.abort === false && ctx.event.dir !== false) {
209+
stopAndPrevent(evt)
210+
document.body.classList.remove('no-pointer-events')
211+
document.body.classList.remove('non-selectable')
212+
}
157213
}
158214
}
159215

quasar/src/directives/TouchSwipe.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,16 +46,16 @@
4646
},
4747

4848
"arg": {
49-
"type": "Number",
50-
"desc": "Amount of time to wait (in milliseconds) to determine if it was a swipe indeed",
51-
"default": 300,
49+
"type": "String",
50+
"desc": "x:y:z, where x is minimum velocity (dist/time), y is minimum distance on first move on mobile, z is minimum distance on desktop until deciding if it's a swipe indeed",
51+
"default": "0.06:6:50",
5252
"examples": [ "v-touch-swipe:400=\"fnToCall\"" ]
5353
},
5454

5555
"modifiers": {
56-
"noMouse": {
56+
"mouse": {
5757
"type": "Boolean",
58-
"desc": "Disregard mouse events and handle only touch events"
58+
"desc": "Listen for mouse events too"
5959
},
6060

6161
"horizontal": {

0 commit comments

Comments
 (0)