Reputation: 23
I'm using a slideshow component from our library of components which gets swipe events from a utility function that's initialized on mount. The problem I'm facing is while testing on phone I found that once you tap on a link in a slide from that slideshow, a swipe event fires along with a click.
this is the util function: `
function initSwipeEvents(el, deltaMin = 80) {
const swipeData = {
startX: 0,
startY: 0,
endX: 0,
endY: 0,
}
let directionEvents = []
el.addEventListener("touchstart", (e) => {
const t = e.touches[0]
swipeData.startX = t.screenX
swipeData.startY = t.screenY
})
el.addEventListener("touchmove", (e) => {
const t = e.touches[0]
swipeData.endX = t.screenX
swipeData.endY = t.screenY
})
el.addEventListener("touchend", () => {
const deltaX = swipeData.endX - swipeData.startX
const deltaY = swipeData.endY - swipeData.startY
if (Math.abs(deltaX) > deltaMin) {
if (deltaX > 0) directionEvents.push("right")
else directionEvents.push("left")
}
if (Math.abs(deltaY) > deltaMin) {
if (deltaY > 0) directionEvents.push("down")
else directionEvents.push("up")
}
directionEvents.forEach((direction) =>
el.dispatchEvent(new Event(`swipe-${direction}`))
)
directionEvents = []
})
}
export default initSwipeEvents
`
This is the slideshow component: `
<div
class="slideshow"
tabindex="0"
@swipe-down="goToPrev"
@swipe-up="goToNext"
>
<div
v-show="activeSlideLogic(i, internalIdx)"
class="slide"
>
<slot
:slide="slide"
name="slide"
/>
</div>
</div>
<script>
mounted() {
if (this.swipeEvents) initSwipeEvents(this.$el) **// swipeEvents is just a boolean prop**
},
methods:{
getLoopedIdx(idx) {
if (this.wrap)
return (idx + this.slides.length) % this.slides.length
else return _clamp(idx, 0, this.slides.length - 1)
},
goToNext() {
this.$nextTick(
() =>
(this.internalIdx = this.getLoopedIdx(this.internalIdx + 1))
)
},
goToPrev() {
this.$nextTick(
() =>
(this.internalIdx = this.getLoopedIdx(this.internalIdx - 1))
)
},
}
</script>
` This is the slide components that is used in the slideshow slot:
<div class="slide-video">
<wp-image **// this is a custom image component, shouldn't be causing the issue**
class="image"
:image="image"
>
<nuxt-link **// this is the link I'm referencing**
class="title-meta"
:to="to"
>
<div class="title-wrapper">
<svg-play class="svg-play" />
<h2
class="title"
v-html="title"
/>
</div>
</nuxt-link>
</wp-image>
</div>
I tried to prevent the default action by doing the folowing: `
function initSwipeEvents(el, deltaMin = 80) {
const swipeData = {
startX: 0,
startY: 0,
endX: 0,
endY: 0,
}
let directionEvents = []
el.addEventListener("touchstart", (e) => {
const t = e.touches[0]
swipeData.startX = t.screenX
swipeData.startY = t.screenY
// added
console.log(e.target);
if( e.target.matches('.title-meta') ||
e.target.matches('.title-meta *')){
console.log("this is a link");
e.preventDefault();
}
})
el.addEventListener("touchmove", (e) => {
const t = e.touches[0]
swipeData.endX = t.screenX
swipeData.endY = t.screenY
// added
console.log(e.target);
if( e.target.matches('.title-meta') ||
e.target.matches('.title-meta *')){
console.log("this is a link");
e.preventDefault();
}
})
el.addEventListener("touchend", () => {
const deltaX = swipeData.endX - swipeData.startX
const deltaY = swipeData.endY - swipeData.startY
if (Math.abs(deltaX) > deltaMin) {
if (deltaX > 0) directionEvents.push("right")
else directionEvents.push("left")
}
if (Math.abs(deltaY) > deltaMin) {
if (deltaY > 0) directionEvents.push("down")
else directionEvents.push("up")
}
directionEvents.forEach((direction) =>
el.dispatchEvent(new Event(`swipe-${direction}`))
)
directionEvents = []
})
}
export default initSwipeEvents
` I also tried the css property, touch-action: none; on the link in the slide, to no avail
I expected to be able to click on the link without triggering the swipe event. I'm not sure where to implement the change, whether on the util or on the slideshow it's self or if the change I implemented is correct.
Edit: I have tried adding
goToNext(e) {
console.log(e)
this.$nextTick(
() =>
(this.internalIdx = this.getLoopedIdx(this.internalIdx + 1))
)
},
goToPrev(e) {
console.log(e)
this.$nextTick(
() =>
(this.internalIdx = this.getLoopedIdx(this.internalIdx - 1))
)
},
...on the slideshow its self, the console.log is always logging that I'm targeting the div "target: div.slideshow", even when clicking on the link. While if I log the onWheel method, which listens to the wheel event (it isn't being imported form a utilty), I', getting the expected result. I think the util might not have the correct scope it needs, as it;s bound to the $el, which is slideshow.
Upvotes: 1
Views: 127
Reputation: 23
I found out the solution on my own. Basically what was happening is that the utility function listens for the touchStart, touchMove and touchEnd events. But if only a tap of a finger happens, there is no touchMove event firing. TouchEnd event is subtracting touchStart and touchMove data (screenX & screenY). So result is always bigger then deltaMin and the custom swipe event is triggered. The solution is to take out the touchMove event and add its logic to touchEnd event.
Upvotes: 1