最早期的事件绑定方式,直接在HTML中编写事件处理代码。
<button onclick="console.log('点击了')">按钮</button>
<button onclick="alert('Hello')">点击</button>
<div onmouseover="this.style.background='red'" onmouseout="this.style.background=''">
鼠标移入移出
</div>
<button onclick="handleClick()">按钮</button>
<button onclick="handleClickWithEvent(event)">传递事件</button>
<script>
function handleClick() {
console.log("按钮被点击");
}
function handleClickWithEvent(e) {
console.log("事件对象:", e);
console.log("事件类型:", e.type);
}
</script>
<!-- 问题1:HTML与JS混合,难以维护 -->
<button onclick="if(confirm('确定吗?')){submit()}">提交</button>
<!-- 问题2:时序问题,函数可能未定义 -->
<button onclick="handleClick()">按钮</button>
<script src="external.js" defer></script>
<!-- 问题3:作用域问题 -->
<button onclick="console.log(this)">this指向button</button>
<!-- 不推荐 -->
<button onclick="doSomething()">按钮</button>
<!-- 推荐 -->
<button id="myButton">按钮</button>
<script>
document.getElementById("myButton").addEventListener("click", doSomething);
</script>
通过元素属性赋值的方式绑定事件。
const button = document.querySelector("button");
// 赋值方式绑定
button.onclick = function() {
console.log("按钮被点击");
};
// 移除事件
button.onclick = null;
const button = document.querySelector("button");
button.onclick = function() {
console.log(this); // button元素
console.log(this === button); // true
};
button.onclick = function(event) {
console.log(event); // 事件对象
console.log(event.type); // "click"
console.log(event.target);
};
const button = document.querySelector("button");
// 只能绑定一个处理程序
button.onclick = function() {
console.log("处理程序1");
};
button.onclick = function() {
console.log("处理程序2"); // 覆盖了第一个
};
// 点击只输出 "处理程序2"
使用addEventListener和removeEventListener方法。
const button = document.querySelector("button");
// 基本语法
// element.addEventListener(type, handler, options)
button.addEventListener("click", function() {
console.log("点击了");
});
// 可以绑定多个处理程序
button.addEventListener("click", function() {
console.log("处理程序1");
});
button.addEventListener("click", function() {
console.log("处理程序2");
});
// 两个函数都会执行
const button = document.querySelector("button");
function handleClick() {
console.log("点击了");
}
// 添加
button.addEventListener("click", handleClick);
// 移除 - 必须是同一个函数引用
button.removeEventListener("click", handleClick);
// 注意:匿名函数无法移除
button.addEventListener("click", function() {
console.log("无法移除");
});
// button.removeEventListener("click", function() {...}); // 无效
const button = document.querySelector("button");
// 布尔值:是否在捕获阶段触发
button.addEventListener("click", handler, false); // 冒泡阶段(默认)
button.addEventListener("click", handler, true); // 捕获阶段
// 配置对象
button.addEventListener("click", handler, {
capture: false, // 是否捕获阶段
once: true, // 是否只执行一次
passive: true, // 是否不会调用preventDefault
signal: controller.signal // AbortSignal,用于取消
});
const button = document.querySelector("button");
// 只执行一次后自动移除
button.addEventListener("click", function() {
console.log("只执行一次");
}, { once: true });
// 提升滚动性能
document.addEventListener("touchstart", function(e) {
// 不会调用e.preventDefault()
}, { passive: true });
// passive: true 表示不会调用preventDefault
// 浏览器可以立即开始滚动,不用等待JS执行完
const button = document.querySelector("button");
const controller = new AbortController();
button.addEventListener("click", function() {
console.log("点击");
}, { signal: controller.signal });
// 取消事件监听
controller.abort();
旧版IE使用attachEvent和detachEvent(已废弃)。
// IE8及以下
if (element.attachEvent) {
element.attachEvent("onclick", function() {
console.log("点击");
});
}
// 移除
element.detachEvent("onclick", handler);
// 注意:事件名需要加on前缀
// this指向window而不是元素
const EventUtil = {
addHandler: function(element, type, handler) {
if (element.addEventListener) {
element.addEventListener(type, handler, false);
} else if (element.attachEvent) {
element.attachEvent("on" + type, handler);
} else {
element["on" + type] = handler;
}
},
removeHandler: function(element, type, handler) {
if (element.removeEventListener) {
element.removeEventListener(type, handler, false);
} else if (element.detachEvent) {
element.detachEvent("on" + type, handler);
} else {
element["on" + type] = null;
}
}
};
// 使用
EventUtil.addHandler(button, "click", handleClick);
EventUtil.removeHandler(button, "click", handleClick);
深入理解事件监听器的工作原理。
const button = document.querySelector("button");
button.addEventListener("click", function handler1() {
console.log("handler1");
});
button.addEventListener("click", function handler2() {
console.log("handler2");
});
button.addEventListener("click", function handler3() {
console.log("handler3");
});
// 点击时按添加顺序执行: handler1 → handler2 → handler3
const button = document.querySelector("button");
function handler() {
console.log("点击");
}
// 同一个函数可以添加多次
button.addEventListener("click", handler);
button.addEventListener("click", handler);
button.addEventListener("click", handler);
// 点击会执行3次
// Chrome DevTools方法(非标准)
// getEventListeners(element)
// 在控制台中
// getEventListeners(document.querySelector("button"))
正确移除事件监听器的方法。
const button = document.querySelector("button");
function handleClick() {
console.log("点击");
}
button.addEventListener("click", handleClick);
// 移除
button.removeEventListener("click", handleClick);
// 正确:使用命名函数
function handler() {
console.log("点击");
}
element.addEventListener("click", handler);
element.removeEventListener("click", handler);
// 错误:匿名函数无法移除
element.addEventListener("click", function() {
console.log("点击");
});
element.removeEventListener("click", function() { // 不同的函数
console.log("点击");
});
const button = document.querySelector("button");
// 保存引用
const handler = () => console.log("点击");
button.addEventListener("click", handler);
button.removeEventListener("click", handler); // 可以移除
// 直接写无法移除
button.addEventListener("click", () => console.log("点击"));
// 无法移除
const button = document.querySelector("button");
const obj = {
name: "东巴文",
handleClick: function() {
console.log(this.name);
}
};
// bind返回新函数
const boundHandler = obj.handleClick.bind(obj);
button.addEventListener("click", boundHandler);
button.removeEventListener("click", boundHandler); // 可以移除
// 注意:每次bind都是新函数
button.addEventListener("click", obj.handleClick.bind(obj));
button.removeEventListener("click", obj.handleClick.bind(obj)); // 无效!
// 使用once选项
button.addEventListener("click", handler, { once: true });
// 使用AbortController
const controller = new AbortController();
button.addEventListener("click", handler, { signal: controller.signal });
controller.abort(); // 取消
// 执行一次后移除
function handleOnce() {
console.log("执行一次");
button.removeEventListener("click", handleOnce);
}
button.addEventListener("click", handleOnce);
| 方式 | 多处理程序 | 可移除 | 捕获控制 | 东巴文建议 |
|---|---|---|---|---|
| HTML属性 | 否 | 难 | 否 | 不推荐 |
| DOM0级 | 否 | 简单 | 否 | 简单场景 |
| DOM2级 | 是 | 需引用 | 是 | 推荐 |
掌握了事件绑定后,让我们继续学习:
东巴文(db-w.cn) - 让编程学习更简单
🎯 东巴文寄语:事件绑定是前端交互的基础,推荐使用addEventListener方式,它支持多个处理程序、可以控制事件流阶段、还能精确移除。在 db-w.cn,我们帮你掌握事件绑定的最佳实践!