阻止在显示浮层后通过按“ENTER”键触发按钮的点击事件

huangapple go评论56阅读模式
英文:

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 &quot;react&quot;;
import { useOverlay } from &quot;./OverlayContext&quot;;

function Dashboard() {
  const { CreateOverlay } = useOverlay();

  function handleClick(e) {
    e.preventDefault();
    e.stopPropagation();
    CreateOverlay(&quot;Now press ENTER and it will trigger again.&quot;);
  }

  return (
    &lt;&gt;
      &lt;div&gt;Click the button!&lt;/div&gt;
      &lt;button onClick={(e) =&gt; handleClick(e)}&gt; Show overlay &lt;/button&gt;
    &lt;/&gt;
  );
}

export default Dashboard;

Overlay context:

import { createContext, useContext, useState } from &quot;react&quot;;

export const OverlayContext = createContext();

export function useOverlay() {
  return useContext(OverlayContext);
}

export const OverlayProvider = ({ children }) =&gt; {
  const [overlays, setOverlays] = useState([]);

  function CreateOverlay(text) {
    return setOverlays((o) =&gt; {
      return [...o, { text }];
    });
  }

  return (
    &lt;OverlayContext.Provider value={{ CreateOverlay }}&gt;
      {overlays.length &gt; 0 &amp;&amp;
        overlays.map((o, index) =&gt; (
          &lt;div className=&quot;overlay&quot; key={index}&gt;
            {o.text}
          &lt;/div&gt;
        ))}
      {children}
    &lt;/OverlayContext.Provider&gt;
  );
};

答案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(&quot;Now press ENTER and it will trigger again.&quot;);
    e.target.blur();
  }

阻止在显示浮层后通过按“ENTER”键触发按钮的点击事件

答案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 &quot;react&quot;;
export const OverlayContext = createContext();
export function useOverlay() {
return useContext(OverlayContext);
}
export const OverlayProvider = ({ children }) =&gt; {
const [overlays, setOverlays] = useState([]);
const buttonFocusRef = useRef(null);
function CreateOverlay(text) {
return setOverlays((o) =&gt; {
return [...o, { id: Math.random() * 100, text }];
});
}
function DeleteOverlay(id) {
setOverlays(overlays.filter((o) =&gt; o.id !== id));
return;
}
useEffect(() =&gt; {
console.log(&quot;[Debug] Overlays length:&quot;, overlays.length);
}, [overlays]);
useEffect(() =&gt; {
if (overlays.length &gt; 0 &amp;&amp; buttonFocusRef !== null) {
buttonFocusRef.current.focus();
}
}, [overlays, buttonFocusRef]);
return (
&lt;OverlayContext.Provider value={{ CreateOverlay }}&gt;
{overlays.length &gt; 0 &amp;&amp;
overlays.map((o, index) =&gt; (
&lt;div className=&quot;overlay&quot; key={index}&gt;
{o.text}
&lt;button
className=&quot;btn&quot;
onClick={() =&gt; DeleteOverlay(o.id)}
ref={buttonFocusRef}
&gt;
Click to cancel overlay
&lt;/button&gt;
&lt;/div&gt;
))}
{children}
&lt;/OverlayContext.Provider&gt;
);
};

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=&quot;0&quot; for the focus to work.

huangapple
  • 本文由 发表于 2023年3月4日 04:05:10
  • 转载请务必保留本文链接:https://go.coder-hub.com/75631443.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定