在JavaScript中自动将焦点设置到按钮上

前端开发 2026-07-09

我在用JavaScript实现自动按钮聚焦时遇到困难。假设我们有一个非常复杂的应用界面,需要在焦点丢失后将焦点重新放回到某些按钮上。例如,下面图片所示,我们有若干个按钮:

HTML 与 CSS 中的若干按钮

如你所见,第一个按钮处于焦点状态(绿色轮廓)。我希望所有绿色按钮都能获得焦点,点击红色按钮后应在大约一秒后把焦点返回到最后一个获得焦点的绿色按钮。遗憾的是,我的代码行为异常,因为无论点击哪个按钮,焦点都会在一秒后回到第一个按钮。下面是我的代码。

var focusOn = document.querySelectorAll('[data-focusable]')[0];

const setFocus = (targetName) => {
  if (targetName.getAttribute('data-focusable') === 'true') {
    targetName.focus({
      preventScroll: true
    });
    ['focusout', 'blur'].forEach((eventName) => {
      targetName.addEventListener(eventName, (event) => {
        focusOn = event.target;
        if (focusOn.getAttribute('data-focusable') === 'true') {
          setTimeout(() => {
            focusOn.focus({
              preventScroll: true
            });
          }, 1000);
        } else {
          event.target.focus({
            preventScroll: true
          });
        }
      });
    });
  }
}

setFocus(focusOn);
button:focus {
  outline: 2px solid green;
}

button[data-focusable="true"] {
  color: green;
}

button[data-focusable="false"] {
  color: red;
}
<button data-focusable="true">Button 1</button>
<button data-focusable="true">Button 2</button>
<button data-focusable="false">Button 3</button>
<button data-focusable="true">Button 4</button>
<button data-focusable="false">Button 5</button>
<button data-focusable="false">Button 6</button>
<button data-focusable="true">Button 7</button>

问题在于触发事件的主要因素不是对应用用户的某种反应(例如鼠标点击或按键),而是应用中某个元素的焦点丢失。

如果有人有任何想法,请回复。谢谢。

JSFiddle

编辑


还有其他折衷方案,但并不总能为我解决问题。下面是我发现的:

var buttons = document.querySelectorAll('button');
var focusedButton = document.querySelector('button:focus');

buttons.forEach(button => {
  button.addEventListener('focus', (event) => {
    if (!event.target.classList.contains('focusable')) {
      focusedButton.focus();
    } else {
      event.target.focus();
      focusedButton = event.target;
    }
  });
});
button:focus {
  outline: 2px solid green;
}

button.focusable {
  color: green;
}

button.non-focusable {
  color: red;
}
<button class="focusable">Button 1</button>
<button class="focusable">Button 2</button>
<button class="non-focusable">Button 3</button>
<button class="focusable">Button 4</button>
<button class="non-focusable">Button 5</button>
<button class="non-focusable">Button 6</button>
<button class="focusable">Button 7</button>

抱歉打扰您。

解决方案

Here's my take at this problem:

  • 通过事件代理实现对动态元素的支持
  • 支持无需先前绿色聚焦的红色按钮的即时点击(其实是 pointerdown
  • 使用 clearTimeout() 实现更好的用户体验(在发生红色 pointerdown 之后通过Tab键聚焦到一个绿色按钮)
  • 支持在不重新聚焦到任何按钮的情况下清除窗口焦点
let lastFoc;
let tOutFoc;

const handleFocusable = (ev) => {
  const el = ev.target.closest(`[data-focusable]`);
  if (!el) return; // Not a button of interest
  if (ev.type === "focusin" && el.dataset.focusable === "true") {
    clearTimeout(tOutFoc); // Better UX - prevents weird glitches if user tabs to green after a red click
    lastFoc = el; // Remember focus on focusin
  } else if (ev.type === "pointerdown") {
    const elToFocus = lastFoc ?? document.querySelector(`[data-focusable]`);
    tOutFoc = setTimeout(() => elToFocus?.focus({ preventScroll: true }), 1000); // Reset focus on click
  }
};

addEventListener("focusin", handleFocusable);
addEventListener("pointerdown", handleFocusable);
button:focus {
  outline: 2px solid green;
}

button[data-focusable="true"] {
  color: green;
}
<button data-focusable="true"><i>Button 1</i></button>
<button data-focusable="true">Button 2</button>
<button data-focusable="false">Button 3</button>
<button data-focusable="true">Button 4</button>
<button data-focusable="false">Button 5</button>
<button data-focusable="false">Button 6</button>
<button data-focusable="true">Button 7</button>
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章