Bin*_*iya 19 dom-events reactjs react-web create-react-app
有没有办法在react-web应用程序中添加长按事件?
我有地址列表.长按任何地址,我想触发事件删除该地址,然后是确认框.
sud*_*ang 36
您可以使用MouseDown,MouseUp,TouchStart,TouchEnd事件来控制可以充当长按事件的计时器.看看下面的代码
class App extends Component {
constructor() {
super()
this.handleButtonPress = this.handleButtonPress.bind(this)
this.handleButtonRelease = this.handleButtonRelease.bind(this)
}
handleButtonPress () {
this.buttonPressTimer = setTimeout(() => alert('long press activated'), 1500);
}
handleButtonRelease () {
clearTimeout(this.buttonPressTimer);
}
render() {
return (
<div
onTouchStart={this.handleButtonPress}
onTouchEnd={this.handleButtonRelease}
onMouseDown={this.handleButtonPress}
onMouseUp={this.handleButtonRelease}
onMouseLeave={this.handleButtonRelease}>
Button
</div>
);
}
}
Run Code Online (Sandbox Code Playgroud)
小智 32
在react 16.8中使用钩子时,您可以使用函数和钩子重写类。
import { useState, useEffect } from 'react';
export default function useLongPress(callback = () => {}, ms = 300) {
const [startLongPress, setStartLongPress] = useState(false);
useEffect(() => {
let timerId;
if (startLongPress) {
timerId = setTimeout(callback, ms);
} else {
clearTimeout(timerId);
}
return () => {
clearTimeout(timerId);
};
}, [startLongPress]);
return {
onMouseDown: () => setStartLongPress(true),
onMouseUp: () => setStartLongPress(false),
onMouseLeave: () => setStartLongPress(false),
onTouchStart: () => setStartLongPress(true),
onTouchEnd: () => setStartLongPress(false),
};
}
Run Code Online (Sandbox Code Playgroud)
import useLongPress from './useLongPress';
function MyComponent (props) {
const backspaceLongPress = useLongPress(props.longPressBackspaceCallback, 500);
return (
<Page>
<Button {...backspaceLongPress}>
Click me
</Button>
</Page>
);
};
Run Code Online (Sandbox Code Playgroud)
Huo*_*yen 11
好钩!但我想做一点改进。使用useCallback包事件处理程序。这样可以确保这些值不会在每次渲染时都改变。
import { useState, useEffect, useCallback } from 'react';
export default function useLongPress(callback = () => {}, ms = 300) {
const [startLongPress, setStartLongPress] = useState(false);
useEffect(() => {
let timerId;
if (startLongPress) {
timerId = setTimeout(callback, ms);
} else {
clearTimeout(timerId);
}
return () => {
clearTimeout(timerId);
};
}, [startLongPress]);
const start = useCallback(() => {
setStartLongPress(true);
}, []);
const stop = useCallback(() => {
setStartLongPress(false);
}, []);
return {
onMouseDown: start,
onMouseUp: stop,
onMouseLeave: stop,
onTouchStart: start,
onTouchEnd: stop,
};
}
Run Code Online (Sandbox Code Playgroud)
基于@Sublime me 上面关于避免多次重新渲染的评论,我的版本不使用任何触发渲染的内容:
export function useLongPress({
onClick = () => {},
onLongPress = () => {},
ms = 300,
} = {}) {
const timerRef = useRef(false);
const eventRef = useRef({});
const callback = useCallback(() => {
onLongPress(eventRef.current);
eventRef.current = {};
timerRef.current = false;
}, [onLongPress]);
const start = useCallback(
(ev) => {
ev.persist();
eventRef.current = ev;
timerRef.current = setTimeout(callback, ms);
},
[callback, ms]
);
const stop = useCallback(
(ev) => {
ev.persist();
eventRef.current = ev;
if (timerRef.current) {
clearTimeout(timerRef.current);
onClick(eventRef.current);
timerRef.current = false;
eventRef.current = {};
}
},
[onClick]
);
return useMemo(
() => ({
onMouseDown: start,
onMouseUp: stop,
onMouseLeave: stop,
onTouchStart: start,
onTouchEnd: stop,
}),
[start, stop]
);
}
Run Code Online (Sandbox Code Playgroud)
它还提供两个onLongPress和onClick并且将接收到的事件对象。
用法与前面描述的一样,除了现在在对象中传递参数之外,所有参数都是可选的:
const longPressProps = useLongPress({
onClick: (ev) => console.log('on click', ev.button, ev.shiftKey),
onLongPress: (ev) => console.log('on long press', ev.button, ev.shiftKey),
});
// and later:
return (<button {...longPressProps}>click me</button>);
Run Code Online (Sandbox Code Playgroud)
这是我在生产中使用的东西,受到原始答案的启发。如果下面有错误,那么我想我在生产中遇到了错误!\xe2\x80\x8d\xe2\x99\x82\xef\xb8\x8f
\n我想让钩子更加简洁,并在实现需要时允许可组合性(例如:添加快速输入与慢速输入,而不是单个回调)。
\nconst [onStart, onEnd] = useLongPress(() => alert(\'Old School Alert\'), 1000);\n\nreturn (\n <button\n type="button"\n onTouchStart={onStart}\n onTouchEnd={onEnd}\n >\n Hold Me (Touch Only)\n </button>\n)\nRun Code Online (Sandbox Code Playgroud)\n它的实现比看起来更简单。只是多了很多行评论。
\n我添加了一堆注释,因此如果您将其复制/粘贴到代码库中,您的同事可以在 PR 期间更好地理解它。
\nimport {useCallback, useRef} from \'react\';\n\nexport default function useLongPress(\n // callback that is invoked at the specified duration or `onEndLongPress`\n callback : () => any,\n // long press duration in milliseconds\n ms = 300\n) {\n // used to persist the timer state\n // non zero values means the value has never been fired before\n const timerRef = useRef<number>(0);\n\n // clear timed callback\n const endTimer = () => {\n clearTimeout(timerRef.current || 0);\n timerRef.current = 0;\n };\n\n // init timer\n const onStartLongPress = useCallback((e) => {\n // stop any previously set timers\n endTimer();\n\n // set new timeout\n timerRef.current = window.setTimeout(() => {\n callback();\n endTimer();\n }, ms);\n }, [callback, ms]);\n\n // determine to end timer early and invoke the callback or do nothing\n const onEndLongPress = useCallback(() => {\n // run the callback fn the timer hasn\'t gone off yet (non zero)\n if (timerRef.current) {\n endTimer();\n callback();\n }\n }, [callback]);\n\n return [onStartLongPress, onEndLongPress, endTimer];\n}\n\nRun Code Online (Sandbox Code Playgroud)\n示例中使用 500ms 设置。GIF 中的自发圆圈显示了我按下按钮时的情况。
\n\n这是最受欢迎的答案的打字稿版本,以防万一它对任何人有用:
(它还解决了通过使用和克隆事件来访问event委托事件中的属性的问题)timeOute.persist()
import { useCallback, useRef, useState } from "react";
function preventDefault(e: Event) {
if ( !isTouchEvent(e) ) return;
if (e.touches.length < 2 && e.preventDefault) {
e.preventDefault();
}
};
export function isTouchEvent(e: Event): e is TouchEvent {
return e && "touches" in e;
};
interface PressHandlers<T> {
onLongPress: (e: React.MouseEvent<T> | React.TouchEvent<T>) => void,
onClick?: (e: React.MouseEvent<T> | React.TouchEvent<T>) => void,
}
interface Options {
delay?: number,
shouldPreventDefault?: boolean
}
export default function useLongPress<T>(
{ onLongPress, onClick }: PressHandlers<T>,
{ delay = 300, shouldPreventDefault = true }
: Options
= {}
) {
const [longPressTriggered, setLongPressTriggered] = useState(false);
const timeout = useRef<NodeJS.Timeout>();
const target = useRef<EventTarget>();
const start = useCallback(
(e: React.MouseEvent<T> | React.TouchEvent<T>) => {
e.persist();
const clonedEvent = {...e};
if (shouldPreventDefault && e.target) {
e.target.addEventListener(
"touchend",
preventDefault,
{ passive: false }
);
target.current = e.target;
}
timeout.current = setTimeout(() => {
onLongPress(clonedEvent);
setLongPressTriggered(true);
}, delay);
},
[onLongPress, delay, shouldPreventDefault]
);
const clear = useCallback((
e: React.MouseEvent<T> | React.TouchEvent<T>,
shouldTriggerClick = true
) => {
timeout.current && clearTimeout(timeout.current);
shouldTriggerClick && !longPressTriggered && onClick?.(e);
setLongPressTriggered(false);
if (shouldPreventDefault && target.current) {
target.current.removeEventListener("touchend", preventDefault);
}
},
[shouldPreventDefault, onClick, longPressTriggered]
);
return {
onMouseDown: (e: React.MouseEvent<T>) => start(e),
onTouchStart: (e: React.TouchEvent<T>) => start(e),
onMouseUp: (e: React.MouseEvent<T>) => clear(e),
onMouseLeave: (e: React.MouseEvent<T>) => clear(e, false),
onTouchEnd: (e: React.TouchEvent<T>) => clear(e)
};
};
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
11040 次 |
| 最近记录: |