英文:
Prevent onClick (using ENTER) on a button after overlay shown
问题
I have a button and when I click, its shown an overlay with width 100%
, height 100%
and position: absolute
. The problem is that, after I click the button to show the overlay, I can press enter and the overlay will show again (2x times). I need to prevent this. I have already z-index set and is still happening. I want also to say, an overlay can be also be shown without being clicked (I have some custom functions/timers) and also there can be more than an overlay, but I don't want the user to be able to create another one when he is pressing enter
after showing the overlay at the same button (or navigate through buttons/button focus). I'm using Reactjs, this is the full code: Link to the code sandbox
Dashboard:
import React from "react";
import { useOverlay } from "./OverlayContext";
function Dashboard() {
const { CreateOverlay } = useOverlay();
function handleClick(e) {
e.preventDefault();
e.stopPropagation();
CreateOverlay("Now press ENTER and it will trigger again.");
}
return (
<>
<div>Click the button!</div>
<button onClick={(e) => handleClick(e)}> Show overlay </button>
</>
);
}
export default Dashboard;
Overlay context:
import { createContext, useContext, useState } from "react";
export const OverlayContext = createContext();
export function useOverlay() {
return useContext(OverlayContext);
}
export const OverlayProvider = ({ children }) => {
const [overlays, setOverlays] = useState([]);
function CreateOverlay(text) {
return setOverlays((o) => {
return [...o, { text }];
});
}
return (
<OverlayContext.Provider value={{ CreateOverlay }}>
{overlays.length > 0 &&
overlays.map((o, index) => (
<div className="overlay" key={index}>
{o.text}
</div>
))}
{children}
</OverlayContext.Provider>
);
};
英文:
I have a button and when I click, its shown an overlay with width 100%
, height 100%
and position: absolute
.
The problem is that, after I click the button to show the overlay, I can press enter and the overlay will show again (2x times).
I need to prevent this. I have already z-index set and is still happening.
I want also to say, an overlay can be also be shown without being clicked (I have some custom functions/timers) and also there can be more than an overlay, but I don't want the user to be able to create another one when he is pressing enter
after showing the overlay at the same button (or navigate through buttons/button focus).
I'm using Reactjs, this is the full code: https://codesandbox.io/s/pensive-phoebe-74jtej
Dashboard:
import React from "react";
import { useOverlay } from "./OverlayContext";
function Dashboard() {
const { CreateOverlay } = useOverlay();
function handleClick(e) {
e.preventDefault();
e.stopPropagation();
CreateOverlay("Now press ENTER and it will trigger again.");
}
return (
<>
<div>Click the button!</div>
<button onClick={(e) => handleClick(e)}> Show overlay </button>
</>
);
}
export default Dashboard;
Overlay context:
import { createContext, useContext, useState } from "react";
export const OverlayContext = createContext();
export function useOverlay() {
return useContext(OverlayContext);
}
export const OverlayProvider = ({ children }) => {
const [overlays, setOverlays] = useState([]);
function CreateOverlay(text) {
return setOverlays((o) => {
return [...o, { text }];
});
}
return (
<OverlayContext.Provider value={{ CreateOverlay }}>
{overlays.length > 0 &&
overlays.map((o, index) => (
<div className="overlay" key={index}>
{o.text}
</div>
))}
{children}
</OverlayContext.Provider>
);
};
答案1
得分: 2
Pressing enter
will trigger the button again, so you need to blur
from the button after clicking.
按下 enter
将再次触发按钮,所以你需要在点击后从按钮上执行 blur
。
英文:
Pressing enter
will trigger the button again, so you need to blur
from the button after clicking.
function handleClick(e) {
e.preventDefault();
e.stopPropagation();
CreateOverlay("Now press ENTER and it will trigger again.");
e.target.blur();
}
答案2
得分: 0
在经过多次测试和研究后,我发现我可以专注于一个会出现在叠加层中的按钮。
解决方案:
我只是在叠加层内部添加了一个button
,并使用了一个ref
,然后使用useEffect
来使焦点集中在这个特定的按钮上,这将对下一个用户交互有意义,因为下一个用户交互只会发生在叠加层内创建的项目上。
import { createContext, useContext, useState, useEffect, useRef } from "react";
export const OverlayContext = createContext();
export function useOverlay() {
return useContext(OverlayContext);
}
export const OverlayProvider = ({ children }) => {
const [overlays, setOverlays] = useState([]);
const buttonFocusRef = useRef(null);
function CreateOverlay(text) {
return setOverlays((o) => {
return [...o, { id: Math.random() * 100, text }];
});
}
function DeleteOverlay(id) {
setOverlays(overlays.filter((o) => o.id !== id));
return;
}
useEffect(() => {
console.log("[Debug] Overlays length:", overlays.length);
}, [overlays]);
useEffect(() => {
if (overlays.length > 0 && buttonFocusRef !== null) {
buttonFocusRef.current.focus();
}
}, [overlays, buttonFocusRef]);
return (
<OverlayContext.Provider value={{ CreateOverlay }}>
{overlays.length > 0 &&
overlays.map((o, index) => (
<div className="overlay" key={index}>
{o.text}
<button
className="btn"
onClick={() => DeleteOverlay(o.id)}
ref={buttonFocusRef}
>
Click to cancel overlay
</button>
</div>
))}
{children}
</OverlayContext.Provider>
);
};
注意:
在我的第一篇帖子中,源代码中没有按钮,因此如果你需要专注于例如div
,你可以在那个div
上设置ref
,并且你还需要设置tabindex="0"
以使焦点工作。
英文:
After some many testing and research, I've found that I can focus on a button that the overlays will have.
Solution:
I've just added a button
inside the overlay
and with a ref
and then using useEffect
I could make focus on that specific button which will make sense for the next user interaction which will be only on the items created inside overlay
.
import { createContext, useContext, useState, useEffect, useRef } from "react";
export const OverlayContext = createContext();
export function useOverlay() {
return useContext(OverlayContext);
}
export const OverlayProvider = ({ children }) => {
const [overlays, setOverlays] = useState([]);
const buttonFocusRef = useRef(null);
function CreateOverlay(text) {
return setOverlays((o) => {
return [...o, { id: Math.random() * 100, text }];
});
}
function DeleteOverlay(id) {
setOverlays(overlays.filter((o) => o.id !== id));
return;
}
useEffect(() => {
console.log("[Debug] Overlays length:", overlays.length);
}, [overlays]);
useEffect(() => {
if (overlays.length > 0 && buttonFocusRef !== null) {
buttonFocusRef.current.focus();
}
}, [overlays, buttonFocusRef]);
return (
<OverlayContext.Provider value={{ CreateOverlay }}>
{overlays.length > 0 &&
overlays.map((o, index) => (
<div className="overlay" key={index}>
{o.text}
<button
className="btn"
onClick={() => DeleteOverlay(o.id)}
ref={buttonFocusRef}
>
Click to cancel overlay
</button>
</div>
))}
{children}
</OverlayContext.Provider>
);
};
Note:
In my first post I've did not have a button in the source code, so if you have to focus on a div
for example, you can set the ref
on that div
and also you need to set tabindex="0"
for the focus to work.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论