触摸支持在React应用程序上的箭头点击



我正在一个React web应用程序上工作,在那里我有一个4x4griddiv,其中有16个blocks渲染。我有右,左,上,下箭头的箭头点击事件。我需要为那些箭头点击添加移动触摸支持,当它只能在移动设备上访问。我从来没有实现过这些触摸/滑动功能,因此看起来非常令人困惑。如有任何帮助,不胜感激。

组件:

const Grid = () => {
const [grid, setGrid] = useState(new Grid());
const arrowLeftKey = 37;
const arrowDownKey = 40;
const handleKeyDown = (event) => {
if (grid.hasWon()) {
return;
}
if (event.keyCode >= arrowLeftKey && event.keyCode <= arrowDownKey) {
let direction = event.keyCode - arrowLeftKey;
let gridClone = Object.assign(
Object.create(Object.getPrototypeOf(grid)),
grid
);
let newGrid = gridClone.move(direction);
setGrid(newGrid);
}
};
useArrowKeyEvent('keydown',handleKeyDown); //hook
const displayBlocks = grid.cells.map((row, rowIndex) => {
return (
<div key={rowIndex}>
{row.map((col, colIndex) => {
return <Block key={rowIndex + colIndex} />;
})}
</div>
);
});
return (
<div className="grid" id="gridId">            
{displayBlocks}
</div>   
);

我从谷歌中得知我需要使用Touch Events,如touchStart,touchMove,touchEnd。查看touchevents文档,我在组件中添加了以下代码。我将MouseEvents更改为"KeyBoardevent"。因为它是arrow keyclick/keydown事件。但这行不通。不知道我哪里做错了。

const onTouch = (evt) => {
evt.preventDefault();
if (evt.touches.length > 1 || (evt.type === "touchend" && evt.touches.length > 0))
return;

var newEvt = document.createEvent("KeyboardEvent");
var type = null;
var touch = null;

// eslint-disable-next-line default-case
switch (evt.type) {
case "touchstart":
type = "keydown";
touch = evt.changedTouches[0];
break;
case "touchmove":
type = "keydown";
touch = evt.changedTouches[0];
break;
case "touchend":
type = "keydown";
touch = evt.changedTouches[0];
break;
}

newEvt.initEvent(type, true, true, evt.originalTarget.ownerDocument.defaultView, 0,
touch.screenX, touch.screenY, touch.clientX, touch.clientY,
evt.keyCode('37'), evt.keyCode('39'), evt.keyCode('38'), evt.keyCode('40'), 0, null);
evt.originalTarget.dispatchEvent(newEvt);
}

document.addEventListener("touchstart", onTouch, true);
document.addEventListener("touchmove", onTouch, true);
document.addEventListener("touchend", onTouch, true);

当我向右滑动并期望右箭头单击时,我得到以下错误:

TypeError: Cannot read property 'ownerDocument' of undefined

在下面一行代码中:

newEvt.initEvent(type, true, true, evt.originalTarget.ownerDocument.defaultView, 0,
touch.screenX, touch.screenY, touch.clientX, touch.clientY,
evt.keyCode('37'), evt.keyCode('39'), evt.keyCode('38'), evt.keyCode('40'), 0, null);

辑:@sschwei1建议后使用react-swipeable

我在组件中添加了以下部分:

const swipeHandlers = useSwipeable({
onSwipedLeft: useArrowKeyEvent('keydown',handleKeyDown),<<<<<problem 
onSwipedRight: eventData => console.log("swiped right"),
onSwipedUp: eventData => console.log("swiped up"),
onSwipedDown: eventData => console.log("swiped down")
});

和返回语句:

<div className="grid" {...swipeHandlers}>
{displayBlocks}   
</div>

问题:不能使用钩子作为callback函数

React-swipeable是一个为你处理滑动的库,它使你能够为不同的滑动方向创建处理程序,例如onSwipedLeftonSwipedUp以及几乎所有其他你能想到的情况,如onTap,onSwiping,onSwiped,等等。

在这些处理程序中,您可以重用箭头键的逻辑。


我想到的第一个解决方案(不是最漂亮的解决方案,但易于使用和理解)是为swipe创建包装器函数并调用相应的keyHandler函数

下面是这些函数的示例:

const handleTouch = (key) => {
handleKeyDown({keyCode:key});
}

在你的触摸处理程序中你可以用相应的键

调用这个函数
const swipeHandlers = useSwipeable({
onSwipedLeft: () => handleTouch('37'),
onSwipedUp: () => handleTouch('38'),
onSwipedRight: () => handleTouch('39'),
onSwipedDown: () => handleTouch('40')
});

由于您只在handleKeyDown函数中使用keyCode,您可以将具有keyCode属性的对象传递给该函数并"模拟"按键

相关内容

最新更新