如果移动端触摸方法中出现了一些莫名其妙的问题,可以添加下面的代码试试:
- Touch 触摸事件中,在 touchstart 中添加
event.preventDefault)
,阻止移动端浏览器默认行为。- Pointer 指针事件中,加多绑定一个 touchstart 事件并添加
event.preventDefault)
。
Touch 触摸事件是由苹果推出的。
判断浏览器是否支持 Touch 触摸事件。
if ('ontouchstart' in window) {
console.log('支持')
}
触发了 touchend,就不会再触发 touchcancel;触发了 touchcancel,就不会再触发 touchend。所以,一般结束时要执行的方法,在 touchend 和 touchcancel 中都需要绑定。
const box = document.getElementById('box')
// 用手指在屏幕上点击一下,会触发一次 touchsatrt,一次 touchend
box.addEventListener('touchsatrt', () => {console.log('touchsatrt')})
box.addEventListener('touchend', () => {console.log('touchend')})
const box = document.getElementById('box')
box.addEventListener('touchsatrt', (event) => {
console.log(event)
})
type:事件类型。
target:目标元素。
touches:屏幕上所有的触摸点组成的类数组。
targetTouches:类数组。目标元素上所有的触摸点组成的类数组。
changeTouches:类数组。事件触发时,目标元素上状态发生了改变的触摸点组成的类数组。
es 为复数,表明不单支持单指触摸,也支持多指触摸。
例如:以下为一个手机屏幕,在红色背景的元素上绑定了触摸事件。
用三根手指触摸屏幕,落在红色背景的元素中两根,其他区域一根。此时,touches 中有三个触摸点,targetTouches 中有两个触摸点,changeTouches 中有两个触摸点。
其他手指不懂,中间那根手指向右滑动了一下。此时,touches 中有三个触摸点,targetTouches 中有两个触摸点,changeTouches 中有一个触摸点,就是滑动了的那根手机的触摸点。
组成 touches、targetTouches、changeTouches 类数组的 touch 对象就是触摸点。
// 单个触摸点
console.log(event.changeTouches[0])
client 的坐标是不包括滚动条的;page 的坐标是包括滚动条的。
.box {
width: 200px;
height: 200px;
background-color: red;
}
const drag = $el => {
const startPoint = {}
const movePoint = {}
const currPos = {
x: 0,
y: 0,
}
const touchStartHanlder = e => {
e.preventDefault()
const touch = e.changedTouches[0]
startPoint.x = touch.pageX
startPoint.y = touch.pageY
}
const touchMoveHanlder = e => {
const touch = e.changedTouches[0]
movePoint.x = currPos.x + touch.pageX - startPoint.x
movePoint.y = currPos.y + touch.pageY - startPoint.y
$el.style.transform = `translate3d(${movePoint.x}px, ${movePoint.y}px, 0)`
}
const touchEndHanlder = () => {
currPos.x = movePoint.x
currPos.y = movePoint.y
}
// touch 事件是有内定顺序的,只有触发了 touchstart 之后,才会有 touchmove,,然后才会有 touchend 或者 touchcancel,所以可以并排写
$el.addEventListener('touchstart', touchStartHanlder, false)
$el.addEventListener('touchmove', touchMoveHanlder, false)
$el.addEventListener('touchend', touchEndHanlder, false)
$el.addEventListener('touchcancel', touchEndHanlder, false)
}
drag(document.getElementById('box'))
Pointer 指针事件是由微软推出的,统一了鼠标、手指触摸和笔的事件。
判断浏览器是否支持 Pointer 指针事件。
if ('onpointerdown' in window) {
console.log('支持')
}
Pointer 指针事件直接继承了鼠标事件,在鼠标事件的基础上又添加了一些其他内容,处理 Pointer 指针事件和处理鼠标事件几乎一致。
由于pointerover、pointerout 支持事件冒泡,pointerenter、pointerleave 不支持事件冒泡,因此在子元素上进入或离开的时候会触发其父元素的 pointerover、pointerout事件,但是却不会触发 pointerenter、pointerleave 事件。
const box = document.getElementById('box')
box.addEventListener('pointerdown', (event) => {
console.log(event)
})
.box {
width: 200px;
height: 200px;
background-color: red;
}
const drag = $el => {
const startPoint = {}
const movePoint = {}
const currPos = {
x: 0,
y: 0,
}
const pointerMoveHanlder = e => {
movePoint.x = currPos.x + e.pageX - startPoint.x
movePoint.y = currPos.y + e.pageY - startPoint.y
$el.style.transform = `translate3d(${movePoint.x}px, ${movePoint.y}px, 0)`
}
const pointerUpHanlder = () => {
currPos.x = movePoint.x
currPos.y = movePoint.y
document.removeEventListener('pointermove', pointerMoveHanlder, false)
document.removeEventListener('pointerup', pointerUpHanlder, false)
document.removeEventListener('pointercancel', pointerUpHanlder, false)
}
// PC 端鼠标不按下去也会触发 pointermove,所以必须在 pointerdown 的事件处理函数中进行绑定,也就是必须先按下鼠标,才执行拖动、释放等方法
const pointerDownHanlder = e => {
startPoint.x = e.pageX
startPoint.y = e.pageY
// 拖拽之后,元素移动到新的位置,这之间是有时间差的,就会导致触摸点移出目标元素,触摸点移出目标元素后,pointermove 不会再触发,因此,需要将事件处理函数绑定在 document 上
document.addEventListener('pointermove', pointerMoveHanlder, false)
document.addEventListener('pointerup', pointerUpHanlder, false)
document.addEventListener('pointercancel', pointerUpHanlder, false)
}
$el.addEventListener('pointerdown', pointerDownHanlder, false)
// 不加这行代码来阻止移动端的默认事件,移动端将无法拖拽
$el.addEventListener('touchstart', e => {e.preventDefault()}, false)
}
drag(document.getElementById('box'))
如果同时绑定了 touch、pointer、mouse、click 的事件,前三种哪个先触发是不确定的,不同浏览器不同,但是 click 总是最后触发的。
Touch 触摸事件只会在移动端触发,不会在 PC 端触发。
Pointer 指针事件、鼠标事件(mouseover、click 等)在移动端和 PC 端都会触发。
event.preventDefault)
将会阻止鼠标事件(mouseover、click 等)的触发;在 touchmove 中不会阻止。event.preventDefault)
将会阻止 mouse 类事件的触发,不会阻止 click 的触发;在 pointerup 和 pointermove 中全都不会阻止。event.preventDefault)
将会阻止图片默认的拖动行为;在 pointerup 和 pointermove 中全都不会阻止。touch-action
:touch-action
:写在 CSS 中,用于设置移动端触摸操作时浏览器的行为。这个属性用来取消浏览器默认的手势行为。
浏览器默认行为:许多事件会自动触发浏览器执行某些行为。例如:
- 点击一个链接,将会触发导航到该 URL。
- 点击表单的提交按钮,将会触发提交表单到服务器。
- 滚动鼠标滚轮,将会触发滚动条滚动。
- 在文本上按下鼠标按钮并移动,将会触发选中文本。
- 点击鼠标右键,将会触发弹出右键菜单。
- 在图片上按下鼠标按钮并拖动,将会触发图片的拖动。
属性值:
支持某方向上的拖拽,是指按下去后在那个可拖动方向的执行的拖拽。
auto:默认值。完全由浏览器自己决定。
none:禁止默认的拖拽行为。
manipulation:只允许进行滚动和持续缩放,禁止双击缩放。
这个设置可以完美解决移动端 click 事件 300ms 延时的问题。
pan-x
:仅支持横向的默认拖拽行为(禁止纵向的默认拖拽行为)。
pan-y
:仅支持纵向的默认拖拽行为(禁止横向的默认拖拽行为)。
pan-down
:仅支持从下往上的默认拖拽行为(禁止从上往下、横向的默认拖拽行为)。
pan-left
:仅支持从左往右的默认拖拽行为(禁止从右往左、纵向的默认拖拽行为)。
pan-right
:仅支持从右往左的默认拖拽行为(禁止从左往右、纵向的默认拖拽行为)。
.box {
touch-action: manipulation;
}