我需要添加一个简单的左/右滑动手势,以便在移动设备上滑动时“选定”图像循环,类似于单击英雄组件中的按钮,也类似于按键盘上的左/右箭头键
我对 JavaScript 没有太多经验,所以如果有人能告诉我到底要写什么以及在哪里,以便我可以完全完成这个项目。
这是一个演示:http://nufaith.ca/justinatkins/
代码:
Vue.component('hero-bg', {
template: `
<div class="hero-bg">
<div class="hero">
<img id="pushed" :src="selected"/>
</div>
</div>
`,
props: ['selected']
});
Vue.component('hero-bg-empty', {
template: `
<div class="hero-bg">
<div class="hero">
<span style="display:block;height:100px;"></span>
</div>
</div>
`
});
Vue.component('hero', {
template: `
<div>
<topbar v-if="!gridEnabled"></topbar>
<topbar2 v-if="gridEnabled"></topbar2>
<hero-bg :selected="selectedItem.img" v-if="!gridEnabled"></hero-bg>
<hero-bg-empty v-if="gridEnabled"></hero-bg-empty>
<div class="hero-container" v-if="!gridEnabled">
<div class="hero">
<img :src="selectedItem.img" v-if="thing" alt=""/>
</div>
<div class="hero-desc">
<button class="control left" @click="previous">
<i class="zmdi zmdi-chevron-left"></i>
</button>
<span class="hero-desc-title" v-html="title"></span>
<button class="control right" @click="next">
<i class="zmdi zmdi-chevron-right"></i>
</button>
<br/>
<button class="view-all-button" @click="enableGrid">OVERVIEW</button>
</div>
</div>
</div>
`,
data() {
return {
gridEnabled: false,
selected: 0,
thing: true
};
},
computed: {
selectedItem() {
return info[this.selected];
},
title() {
const comma = this.selectedItem.title.indexOf(',');
const len = this.selectedItem.title.length;
const strBeginning = this.selectedItem.title.substring(comma, 0);
const strEnd = this.selectedItem.title.substring(comma, len);
if (this.selectedItem.title.includes(',')) {
return `<span>${strBeginning}<span class="font-regular font-muted">${strEnd}</span></span>`;
}
return this.selectedItem.title;
},
maxImages() {
return info.length - 1;
}
},
created() {
window.addEventListener('keydown', e => {
if (e.keyCode === 37) {
this.previous();
return;
}
if (e.keyCode === 39) {
this.next();
return;
}
});
Event.$on('updateImg', index => {
this.selected = index;
this.gridEnabled = !this.gridEnabled;
});
},
methods: {
next() {
this.selected === this.maxImages ? (this.selected = 0) : (this.selected += 1);
},
previous() {
this.selected === 0 ? (this.selected = this.maxImages) : (this.selected -= 1);
},
enableGrid() {
this.gridEnabled = !this.gridEnabled;
window.scroll(0, 0);
Event.$emit('enableGrid');
}
}
});
这就是我在我的一个项目中实现一个简单的滑动手势的方式。你可以看看这个。
代码:
touchableElement.addEventListener('touchstart', function (event) {
touchstartX = event.changedTouches[0].screenX;
touchstartY = event.changedTouches[0].screenY;
}, false);
touchableElement.addEventListener('touchend', function (event) {
touchendX = event.changedTouches[0].screenX;
touchendY = event.changedTouches[0].screenY;
handleGesture();
}, false);
function handleGesture() {
if (touchendX < touchstartX) {
console.log('Swiped Left');
}
if (touchendX > touchstartX) {
console.log('Swiped Right');
}
if (touchendY < touchstartY) {
console.log('Swiped Up');
}
if (touchendY > touchstartY) {
console.log('Swiped Down');
}
if (touchendY === touchstartY) {
console.log('Tap');
}
}
基本上,这里提到的
touchableElement
,是指将接收触摸事件的DOM Element
。如果您想在整个屏幕上激活滑动选项,那么您可以使用 body
标签作为可触摸元素。或者,您可以将任何特定的 div
元素配置为可触摸元素,以防您只想在该特定的 div
上进行滑动手势。
在此
touchableElement
,我们在这里添加 2 个事件监听器:
touchstart
:
这是用户开始滑动的时间。我们采用初始坐标 (x,y) 和
分别将它们存储到touchstartX、touchstartY中。touchend
:这是用户停止滑动的时间。我们获取最终坐标 (x, y) 并将它们分别存储到 touchendX、touchendY 中。请记住,这些坐标的原点是屏幕的左上角。当您从 从左到右 时,x 坐标会增加,而当您从 从上到下时,y 坐标会增加。
然后,在
handleGesture()
中,我们只需比较这两对坐标(touchstartX,touchstartY)和(touchendX,touchendY),以检测不同类型的滑动手势(上,下,左,右):
touchendX < touchstartX
:表示用户开始以较高的X值滑动并且停止以较低的X值滑动。这意味着,从右向左滑动(向左滑动)。
touchendX > touchstartX
:表示用户开始以较低的X值滑动并且停止以较高的X值滑动。这意味着,从左向右滑动(向右滑动)。
touchendY < touchstartY
:表示用户
开始以较高的Y值滑动并且停止以较低的Y值滑动。这意味着,从下到上滑动(向上滑动)。
touchendY > touchstartY
:表示用户
开始以较低的Y值滑动并且停止以较高的Y值滑动。这意味着,从上到下滑动(向下滑动)。
if
块上添加这 4 个不同事件(向上/向下/向左/向右滑动)的代码,如代码所示。
export default class TouchEvent {
static SWIPE_THRESHOLD = 50; // Minimum difference in pixels at which a swipe gesture is detected
static SWIPE_LEFT = 1;
static SWIPE_RIGHT = 2;
static SWIPE_UP = 3;
static SWIPE_DOWN = 4;
constructor(startEvent, endEvent) {
this.startEvent = startEvent;
this.endEvent = endEvent || null;
}
isSwipeLeft() {
return this.getSwipeDirection() == TouchEvent.SWIPE_LEFT;
}
isSwipeRight() {
return this.getSwipeDirection() == TouchEvent.SWIPE_RIGHT;
}
isSwipeUp() {
return this.getSwipeDirection() == TouchEvent.SWIPE_UP;
}
isSwipeDown() {
return this.getSwipeDirection() == TouchEvent.SWIPE_DOWN;
}
getSwipeDirection() {
if (!this.startEvent.changedTouches || !this.endEvent.changedTouches) {
return null;
}
let start = this.startEvent.changedTouches[0];
let end = this.endEvent.changedTouches[0];
if (!start || !end) {
return null;
}
let horizontalDifference = start.screenX - end.screenX;
let verticalDifference = start.screenY - end.screenY;
// Horizontal difference dominates
if (Math.abs(horizontalDifference) > Math.abs(verticalDifference)) {
if (horizontalDifference >= TouchEvent.SWIPE_THRESHOLD) {
return TouchEvent.SWIPE_LEFT;
} else if (horizontalDifference <= -TouchEvent.SWIPE_THRESHOLD) {
return TouchEvent.SWIPE_RIGHT;
}
// Vertical or no difference dominates
} else {
if (verticalDifference >= TouchEvent.SWIPE_THRESHOLD) {
return TouchEvent.SWIPE_UP;
} else if (verticalDifference <= -TouchEvent.SWIPE_THRESHOLD) {
return TouchEvent.SWIPE_DOWN;
}
}
return null;
}
setEndEvent(endEvent) {
this.endEvent = endEvent;
}
}
如何使用
touchstart
和
touchend
的事件:import TouchEvent from '@/TouchEvent'
let touchEvent = null;
document.addEventListener('touchstart', (event) => {
touchEvent = new TouchEvent(event);
});
document.addEventListener('touchend', handleSwipe);
function handleSwipe(event) {
if (!touchEvent) {
return;
}
touchEvent.setEndEvent(event);
if (touchEvent.isSwipeRight()) {
// Do something
} else if (touchEvent.isSwipeLeft()) {
// Do something different
}
// Reset event for next touch
touchEvent = null;
}
的工作,除非你想避免依赖。他们有很好的文档和示例来帮助入门 我的 Vue 知识几乎一无所知,所以我很担心这会成为盲人引导盲人的场景,但你要做的第一件事就是使用 npm 或 YARN 添加依赖项 - 然后将其添加到顶部您的文件使用
import Hammer from 'hammerjs'
尝试在此行上方添加以下代码:Event.$on('updateImg', index => {
const swipeableEl = document.getElementsByClassName('.hero')[0];
this.hammer = Hammer(swipeableEl)
this.hammer.on('swipeleft', () => this.next())
this.hammer.on('swiperight', () => this.previous())
如果它不起作用,您必须检查开发人员工具/控制台日志以查看是否记录了任何有用的错误。
这个
codepen
import { onMounted, Ref } from 'vue'
export type SwipeCallback = (event: TouchEvent) => void;
export type SwipeOptions = {
directinoal_threshold?: number; // Pixels offset to trigger swipe
};
export const useSwipe = (touchableElement: HTMLElement = null, options: Ref<SwipeOptions> = ref({
directinoal_threshold: 10
})) => {
const touchStartX = ref(0);
const touchEndX = ref(0);
const touchStartY = ref(0);
const touchEndY = ref(0);
onMounted(() => {
if (!touchableElement)
touchableElement = document.body;
touchableElement.addEventListener('touchstart', (event) => {
touchStartX.value = event.changedTouches[0].screenX;
touchStartY.value = event.changedTouches[0].screenY;
}, false);
touchableElement.addEventListener('touchend', (event) => {
touchEndX.value = event.changedTouches[0].screenX;
touchEndY.value = event.changedTouches[0].screenY;
handleGesture(event);
}, false);
});
const onSwipeLeft: Array<SwipeCallback> = [];
const onSwipeRight: Array<SwipeCallback> = [];
const onSwipeUp: Array<SwipeCallback> = [];
const onSwipeDown: Array<SwipeCallback> = [];
const onTap: Array<SwipeCallback> = [];
const addEventListener = (arr: Array<SwipeCallback>, callback: SwipeCallback) => {
arr.push(callback);
};
const handleGesture = (event: TouchEvent) => {
if (touchEndX.value < touchStartX.value && (Math.max(touchStartY.value, touchEndY.value) - Math.min(touchStartY.value, touchEndY.value)) < options.value.directinoal_threshold) {
onSwipeLeft.forEach(callback => callback(event));
}
if (touchEndX.value > touchStartX.value && (Math.max(touchStartY.value, touchEndY.value) - Math.min(touchStartY.value, touchEndY.value)) < options.value.directinoal_threshold) {
onSwipeRight.forEach(callback => callback(event));
}
if (touchEndY.value < touchStartY.value && (Math.max(touchStartX.value, touchEndX.value) - Math.min(touchStartX.value, touchEndX.value)) < options.value.directinoal_threshold) {
onSwipeUp.forEach(callback => callback(event));
}
if (touchEndY.value > touchStartY.value && (Math.max(touchStartX.value, touchEndX.value) - Math.min(touchStartX.value, touchEndX.value)) < options.value.directinoal_threshold) {
onSwipeDown.forEach(callback => callback(event));
}
if (touchEndY.value === touchStartY.value) {
onTap.forEach(callback => callback(event));
}
}
return {
onSwipeLeft: (callback: SwipeCallback) => addEventListener(onSwipeLeft, callback),
onSwipeRight: (callback: SwipeCallback) => addEventListener(onSwipeRight, callback),
onSwipeUp: (callback: SwipeCallback) => addEventListener(onSwipeUp, callback),
onSwipeDown: (callback: SwipeCallback) => addEventListener(onSwipeDown, callback),
onTap: (callback: SwipeCallback) => addEventListener(onTap, callback)
}
}
使用示例:
const { onSwipeLeft, onSwipeRight } = useSwipe(document.body);
onSwipeLeft((e:TouchEvent) => {
//logic
});
答案进行修改:
function registerTouchEvent(element, callback) {
const THRESHOLD = 50 // Minimum difference in pixels at which a swipe gesture is detected
let startEvent, endEvent
element.addEventListener('touchstart', event => startEvent = event)
element.addEventListener('touchend', event => { endEvent = event; callback(getSwipeDirection()) })
function getSwipeDirection() {
if (!startEvent.changedTouches || !endEvent.changedTouches) return
let start = startEvent.changedTouches[0]
let end = endEvent.changedTouches[0]
if (!start || !end) return
let horizontalDifference = start.screenX - end.screenX
let verticalDifference = start.screenY - end.screenY
// Horizontal difference dominates
if (Math.abs(horizontalDifference) > Math.abs(verticalDifference)) {
if (horizontalDifference >= THRESHOLD) return 'left'
if (horizontalDifference <= -THRESHOLD) return 'right'
return null
}
// Vertical or no difference dominates
if (verticalDifference >= THRESHOLD) return 'up'
if (verticalDifference <= -THRESHOLD) return 'down'
return null
}
}
使用方法:
registerTouchEvent(document, callback)
callback
将收到一个字符串 left/right/up/down