事件绑定
移动端的click会存在300ms延迟,移动端的click是点击事件,PC端的click是点击。
比如连着点击两下:
- PC会触发:两次click、一次dbclick
- 移动端:不回触发click、只会触发dbclick
点击事件:第一次点击后,检测300ms,看看会不会有第二次点击操作,如果没有事单击,如果有就是双击。
render() {
return <div>
<button onTouchStart={this.touchstart}
onTouchMove={this.touchmove}
onTouchEnd={this.touchend}>
提交
</button>
</div>;
}
解决方案一:单手指事件模型
在触摸屏设备上,单手指事件模型主要通过 touch 相关的事件来处理。以下是常见的触摸事件:
touchstart:当手指触摸屏幕时触发。可以用来记录触摸的开始位置。
touchmove:手指在屏幕上滑动时触发。可以用来追踪手指的移动位置。
touchend:手指从屏幕上离开时触发。可以用来处理触摸结束后的逻辑。
touchcancel:当触摸事件被系统打断时触发,例如,设备出现电话、通知等中断时。
模拟点击效果,可以监听 touchstart 和 touchend 事件。通过判断触摸的起始位置和结束位置,确定是否是点击操作。如果在一定时间内没有滑动,并且触摸的起始和结束位置几乎相同,则可以认为是一个点击。
class Demo extends React.Component {
// 手指按下:记录手指的起始坐标
touchstart = (ev) => {
console.log('startstartstartstartstart')
let finger = ev.changedTouches[0]; //记录了操作手指的相关信息
this.touchStartTime = Date.now();
this.touch = {
startX: finger.pageX,
startY: finger.pageY,
isMove: false
};
};
// 手指移动:记录手指偏移值,和误差值做对比,分析出是否发生移动
touchmove = (ev) => {
console.log('movemovemovemove')
let finger = ev.changedTouches[0],
{ startX, startY } = this.touch;
let changeX = finger.pageX - startX,
changeY = finger.pageY - startY;
if (Math.abs(changeX) > 10 || Math.abs(changeY) > 10) {
this.touch.isMove = true;
}
};
// 手指离开:根据isMove判断是否是点击
touchend = () => {
console.log('endddddd')
this.touchEndTime = Date.now();
console.log(this.touch.isMove, 'this.touch.isMove')
// 点击操作时间是否小于300ms
if (this.touchEndTime - this.touchStartTime < 300) {
this.touch.isMove = false;
}
let { isMove } = this.touch;
if (isMove) return;
// 说明触发了点击操作
console.log('点击了按钮');
};
}
解决方案二:fastclick(已过时,仍可用)
使用fastclick
插件解决移动端使用click事件的300ms延迟问题,在入口文件导入。注意:可能与其他库或框架冲突
import FastClick from "fastclick"
FastClick.attach(document.body)
handle = ()=>{
....
}
render() {
return <div>
<button onClick={this.handle}>
提交
</button>
</div>;
}
解决方案三:CSS touch-action属性
touch-action
属性允许开发者控制浏览器对触摸手势的默认行为。 将 touch-action
设置为none
可以阻止浏览器对触摸事件的默认处理,包括双击缩放,从而消除 300ms 延迟。
循环事件绑定
在React中,我们给循环「创建」的元素做“循环事件绑定”,是好还是不好?
按常理来说,此类需求用事件委托处理是最好的,但是在React 中,我们循环给元素绑定的合成事件本身就是基于事件委托处理的
,所以无需我们自己再单独的设置事件委托的处理机制
class Demo extends React.Component {
state = {
arr: [{
id: 1,
title: '新闻'
}, {
id: 2,
title: '体育'
}, {
id: 3,
title: '电影'
}]
};
handle = (item) => {
// item:点击这一项的数据
console.log('我点击的是:' + item.title);
};
render() {
let { arr } = this.state;
return <div>
{arr.map(item => {
let { id, title } = item;
return <span key={id}
style={{
padding: '5px 15px',
marginRight: 10,
border: '1px solid #DDD',
cursor: 'pointer'
}}
onClick={this.handle.bind(this, item)}>
{title}
</span>;
})}
</div>;
}
}
在vue中,给当前元素添加事件绑定就是给给它做事件绑定,我们可以给它父级元素做事件委托
,根据事件源判断点击的是哪一个
<template>
<div class="list-container" @click="handleClick">
<div class="item" v-for="(item, index) in items" :key="index">
{{ item }}
</div>
</div>
</template>
<script>
export default {
data() {
return {
items: ['Item 1', 'Item 2', 'Item 3', 'Item 4']
};
},
methods: {
handleClick(event) {
// 获取事件源
const clickedElement = event.target;
// 判断点击的是哪个子元素(例如列表项)
if (clickedElement && clickedElement.classList.contains('item')) {
// 获取点击的列表项的文本内容
const clickedItem = clickedElement.textContent;
console.log(`点击了: ${clickedItem}`);
}
}
}
}
</script>