反应:移动(iPhone)上的onClick需要2次点击?
Posted
技术标签:
【中文标题】反应:移动(iPhone)上的onClick需要2次点击?【英文标题】:React: onClick on Mobile (iPhone) requires 2 taps? 【发布时间】:2020-05-18 22:13:10 【问题描述】:Video demonstrating issue
我有一堆可点击的组件,当点击这些组件时,会在一行中添加一个“卡片”。在台式机上,它工作正常,但在移动设备上(在 iPhone 上测试,似乎对 android 平板电脑不是问题),它需要连续点击同一按钮 2 次才能触发 onClick
功能。
这些组件还具有onMouseEnter
/onMouseLeave
效果,以控制全局状态,进而决定是否应应用多个组件附加 CSS(因此我无法将其设为简单的 CSS 悬停效果) .
我相信鼠标效果会干扰点击事件,但我不知道如何解决这个问题。下面是这个组件的相关代码:
const CardSource = ( addCard, note, setHoveredNote, hoveredNote ) =>
return (
<Source
onClick=() => addCard(note)
onMouseEnter=() => setHoveredNote(note)
onMouseLeave=() => setHoveredNote(null)
className=
hoveredNote && hoveredNote.index === note.index ? "highlight" : null
>
note.letters[0]
</Source>
);
;
此外,一旦按钮被点按两次,悬停效果 CSS 就会“粘”在该按钮上,并且永远不会移动到另一个按钮。这似乎发生在 iPhone 和 Android 平板电脑上。我也希望不再发生这种情况。
我在沙盒中创建了此问题的工作演示,如果在移动设备上查看,您应该能够重现这些问题:https://codesandbox.io/s/mobile-requires-2-taps-i9zri?file=/src/Components/CardSource/CardSource.js
【问题讨论】:
【参考方案1】:您的代码可能存在问题,您使用的鼠标事件不会冒泡。 e.g. mouseenter event.
您可能想尝试使用onMouseOver
代替onMouseEnter
和onMouseOut
代替onMouseLeave
的事件冒泡解决方案。
const CardSource = ( addCard, note, setHoveredNote, hoveredNote ) =>
return (
<Source
onClick=() => addCard(note)
onMouseOver=() => setHoveredNote(note)
onMouseOut=() => setHoveredNote(null)
className=
hoveredNote && hoveredNote.index === note.index ? "highlight" : null
>
note.letters[0]
</Source>
);
;
如果上述方法不起作用,您可以使用事件类型进行调试并基于它执行事件处理。例如
const CardSource = ( addCard, note, setHoveredNote, hoveredNote ) =>
const eventHandler = (event) =>
const type, bubbles = event;
switch(type)
case "mouseover":
case "mouseenter":
setHoveredNote(note);
break;
case "mouseout":
case "mouseleave":
setHoveredNote(null);
case "click":
addCard(note);
if (bubbles) // handle hover state
setHoveredNote(note);
break;
default:
break;
const onClick = (event) => eventHandler(event);
const onMouseOver = (event) => eventHandler(event);
const onMouseOut = (event) => eventHandler(event);
return (
<Source
onClick=onClick
onMouseOver=onMouseOver
onMouseOut=onMouseOut
className=
hoveredNote && hoveredNote.index === note.index ? "highlight" : null
>
note.letters[0]
</Source>
);
;
另请注意,提供箭头函数作为道具会在每次渲染时创建该函数的新实例。所以最好在这种情况下使用 bind 或者只使用捕获参数的函数引用。
【讨论】:
我没有考虑冒泡,所以谢谢你提出这个问题。不幸的是,测试了Over
和Out
而不是Enter
和Leave
,似乎没有区别(除了在方块内输入/离开字母时再次触发的函数)。我还使用了您的调试功能,有趣的是,当我为每个鼠标案例记录 bubbles
属性时 - over
、enter
、out
和 leave
,它们都返回了 true
,即使 @ 987654339@ 和leave
应该是false
?也许那里有提示?
您也可能会考虑处理基于触摸的事件,因为我们试图处理的事件是鼠标事件。看看developer.mozilla.org/en-US/docs/Web/API/Touch_events
是的,我认为触摸事件可能需要成为解决方案。我唯一的问题是它们似乎没有得到很好的支持,并且在与悬停/单击事件同时使用时可能会导致一些问题。感谢您的回答和建议使用事件处理调试功能,非常有帮助【参考方案2】:
你可以只使用 css hover
而不是通过 onMouseEnter
事件添加一个类,它修复了两次点击问题。
Link to sandbox
如果您以编程方式使用触发器进行悬停。您可以通过使用onTouchEnd
事件(在沙盒中评论)来解决两次点击问题。
希望对您有所帮助。
【讨论】:
这绝对是在正确的轨道上,但有几个问题:1)我应该在帖子中提到它,但我不能使用简单的css悬停,因为它设置的状态得到传递给我真实项目中的多个组件,这些组件需要基于此更新 css。 2)onTouchEnd
确实可以在 iPhone 上单击 1 次,但 onTouchEnd
本身不允许点击,所以现在它不能在桌面上运行。 3) 同时激活onTouchEnd
和onClick
使其在我的Android 平板电脑上触发两次(令人沮丧的是,不是在你的沙箱中,而是在我的真实项目中......)
另外,onTouchEnd
是否有任何文档?我之前搜索过触摸事件,但唯一提到的是这个页面:reactjs.org/docs/events.html,它根本没有提供任何相关信息
@damon - MDN Docs。如果 android 是最后一块拼图,您可以检测用户代理并有条件地应用 touchEnd(Hacky,我知道)。
看过所有答案后,我想我必须将touch
事件和用户代理检测结合起来。非常感谢您花时间提供解决方案。【参考方案3】:
我记得有一个类似的问题。对我来说,问题是组件的state 不会立即更改,而只会在执行render()
方法时更改。我相信你可能对你所描述的两种效果的异步性有同样的问题。
我在您的代码中看到的唯一 render()
调用位于 App.test.js
中,我通常将其放在相应的 component.tsx
中。
参考文献
Submit button takes 2 clicks to call function in React React.js events need 2 clicks to execute【讨论】:
@damon 告诉我你的想法。如果我今天有时间,无论如何我都会更深入地研究你的代码。 抱歉耽搁了:关于render()
调用的注释,我相信我的代码示例中的主要render
函数在index.js
中。我不认为这里涉及test.js
文件。关于状态没有立即更新的说明,我不确定这与您的两个参考文献是否相同。我之前也遇到过同样的问题,但在这种情况下,状态在第一次点击时成功更新,但技术上应该更新 2 个:1 个用于悬停,1 个用于单击。它可以在台式机上运行,但不能在移动设备上运行,这让我认为这是两者之间的干扰。【参考方案4】:
使用事件onTouchStart
、onTouchMove
、onTouchEnd
来计算触摸。
【讨论】:
以上是关于反应:移动(iPhone)上的onClick需要2次点击?的主要内容,如果未能解决你的问题,请参考以下文章