focus 和 blur 事件仅触发于原生可聚焦元素(如 input、textarea、button、a[href]、iframe)或显式设置 tabindex/contenteditable 的元素;blur 不冒泡,委托需用 focusout;推荐用 addeventlistener 绑定并同步状态变量。

focus 和 blur 事件只能监听“可聚焦元素”的状态变化,普通 div、span 默认不触发——必须加 tabindex 或 contenteditable 才能用。
哪些元素原生支持 focus/blur
以下元素在未禁用(即无 disabled 属性)时,天然响应 focus 和 blur:
-
input、textarea、select、button -
a[href](带href的链接) iframe- 任何设置了
tabindex属性的元素(如tabindex="0") - 任何设置了
contenteditable="true"的元素
注意:tabindex="-1" 允许脚本调用 .focus(),但不能通过 Tab 键进入;tabindex="0" 表示按 DOM 顺序参与 Tab 流;负值 tabindex 不影响 Tab 顺序,仅用于程序聚焦。
为什么直接写 onfocus/onblur 容易出问题
内联写法看似简单,但有明确缺陷:
-
onfocus和onblur是单值属性,重复赋值会覆盖前一个处理函数 - 无法区分用户是否真实输入过(比如清空后失焦,提示文案又恢复,造成体验错乱)
- 在 Vue/React 等框架中,
this.value可能被响应式系统接管,直接操作 DOM 值会失效 - 禁用状态(
disabled)下事件完全不触发,但内联写法没地方做前置判断
推荐统一用 addEventListener:
const input = document.querySelector('input');
let hasInput = false;
input.addEventListener('focus', () => {
if (input.value === '请输入邮箱') {
input.value = '';
}
input.classList.add('focused');
});
input.addEventListener('input', () => {
hasInput = true;
});
input.addEventListener('blur', () => {
if (!input.value && !hasInput) {
input.value = '请输入邮箱';
}
input.classList.remove('focused');
});
blur 事件不冒泡,委托要用 focusout
如果你希望在表单容器上统一监听子输入框的失焦,不能用 blur 绑定在父元素上——它根本不会到达那里。
-
blur和focus都不冒泡,只作用于目标元素自身 - 需要事件委托时,改用
focusout(对应focusin) -
focusout在现代浏览器(IE9+、Chrome、Firefox、Safari)均支持
例如:
const form = document.querySelector('form');
form.addEventListener('focusout', (e) => {
if (e.target.matches('input, textarea')) {
console.log('子输入框失焦:', e.target.name);
}
});
自动聚焦与无障碍注意事项
页面加载后想默认聚焦,别急着写 input.focus():
- 若 DOM 尚未就绪(比如在
<script></script>中同步执行),会报错Cannot read property 'focus' of null - 对屏幕阅读器不友好:强制聚焦可能打断用户当前操作流
- 移动端键盘自动弹出不可控,部分 Android 浏览器会卡顿或不响应
更稳妥的做法是:
- 用 HTML 原生
autofocus属性(语义清晰、由浏览器统一管控) - 确保该输入框是用户流程中的合理起点(比如登录页的账号框)
- 避免在模态框打开后立即
.focus(),应等动画结束、DOM 稳定后再执行
真正容易被忽略的是:焦点状态和 JS 状态变量(如 isFocused)必须严格同步。一旦手动调用 .focus() 或 .blur(),事件不会自动触发,需手动更新状态,否则视觉与逻辑就会脱节。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











