就拿焦点状态来说吧,这问题看着不大,但真正踩过坑的人都清楚,一旦涉及的输入框变多,或者逻辑变得复杂起来,内联写法中那堆 onfocus 和 onblur 简直就是埋雷。说实话,真正能撑住场面的,还得是 addEventListener。 onfocus 和 onblur 这两个属性确实可以配对使用,
onfocus和onblur配对使用: 焦点状态切换技巧
时间:2026-06-17
浏览:532
文章目录
就拿焦点状态来说吧,这问题看着不大,但真正踩过坑的人都清楚,一旦涉及的输入框变多,或者逻辑变得复杂起来,内联写法中那堆 onfocus 和 onblur 简直就是埋雷。说实话,真正能撑住场面的,还得是 addEventListener。

onfocus 和 onblur 这两个属性确实可以配对使用,但问题在于直接写死在 HTML 里很容易失控。一旦涉及响应式状态、条件逻辑,或者需要处理多个输入框,addEventListener 才是更稳妥的选择。
onfocus/onblur 属性只适合最简场景
什么叫最简场景?比如只有一个输入框,没有状态依赖,不涉及校验,也不需要样式联动。那你可以快速写成这样:
但这种写法很快就会暴露问题:
- 你根本分不清用户是“清空后失焦”,还是“从未输入就离开”,结果提示文案动不动就误恢复。
- 想监听
Enter提交或者Tab切换时的焦点流转细节?没门。 - 多个输入框共用同一段内联脚本,维护成本直线上升,出错了都找不到源头。
- 跟 React、Vue 这类框架的状态同步更是麻烦,
this.value很可能被框架劫持,直接失效。
用 addEventListener 实现可维护的焦点状态切换
真正可控的做法是绑定事件监听器,同时配合一个明确的状态变量(比如 isFocused)或者 class 来控制行为。这样做的好处是逻辑清晰,好维护。
- 用
input.addEventListener('focus', ...)捕获聚焦,更新状态或样式。 - 用
input.addEventListener('blur', ...)捕获失焦,触发校验或还原默认值。 - 有个细节要留心:如果你想监听子元素失焦的委托(比如表单容器统一处理),必须用
focusout,因为blur不冒泡。 - 禁用状态下的输入框压根不会触发任何焦点事件,省了你再写
if判断的功夫。
下面这个例子展示的是如何清空提示文本,并避免重复恢复:
const input = document.querySelector('input');
let hasUserInput = false;
input.addEventListener('focus', () => {
if (input.value === '请输入邮箱') {
input.value = '';
input.classList.add('active');
}
});
input.addEventListener('blur', () => {
if (!input.value && !hasUserInput) {
input.value = '请输入邮箱';
input.classList.remove('active');
}
});
input.addEventListener('input', () => {
hasUserInput = true;
});
blur 时机比你想的更微妙
失焦这件事可没那么简单,它不只是“鼠标点开别处”才会发生。以下这些情况都会触发 blur:
- 按
Tab移出当前输入框(哪怕循环到第一个元素也算)。 - 点击页面上其他可聚焦的元素,比如
button、a[href]、其他input。 - 调用
element.blur(),或者切换浏览器标签页(部分浏览器会触发)。 - 但注意,在
document.body上点击不会触发——因为body默认不可聚焦,除非你给它加了tabindex。
所以,别想当然地认为 blur 一定代表“用户完成了填写”,它只是“离开了当前控件”。真正要判断是否提交,还是得以 submit 事件或者显式的按钮点击为准。
autofocus 不等于 JS focus(),别混用
页面加载时想默认聚焦,优先用 HTML 的 autofocus 属性:
而不是在 DOMContentLoaded 里调用 input.focus()。原因有三:
autofocus由浏览器统一管控,兼容屏幕阅读器,还不会打断用户当前正在进行的操作。input.focus()在某些移动端或 iframe 场景下会被静默拒绝,既没报错也没效果,容易让人摸不着头脑。- 如果已经用了
autofocus,JS 里初始的isFocused状态也得设为true,否则状态跟 DOM 就对不上了。
在复杂交互里,焦点状态很容易跟表单校验、无障碍属性(比如 aria-invalid)、CSS 伪类(:focus-within)耦合在一起。动一个地方,就得把整条链都核对一遍。这里想补充一句:先理清“谁该决定焦点何时生效”,再动手写代码,能省下不少麻烦。
实用工具推荐
绿化、压缩、噪点和虚拟水印,自由调节做旧程度。
选择画质和输出格式,预览压缩前后的大小。