说明
比如下面,给一个按钮(元素),绑定点击事件,点击时某个元素的内容变成当前的时间(事件处理程序)
<!-- 格式为:<元素 事件名="函数 或 js代码"></元素> ,单引号双引号都可以,不能混合用 -->
<button onclick='getElementById("demo").innerHTML=Date()'>The time is?</button>
如何监听事件
事件处理程序的名字以”on”开头,因此 click 事件的处理程序叫作 onclick,而 load 事件的处理程序叫作 onload。
方式1、元素的HTML属性监听
通过HTML元素的事件属性来实现
<!-- 直接放入JS代码 或者 函数 -->
<button onClick="console.log(123)">click</button>
<button onClick="divClick()">click</button>
<!-- this 值相当于事件的目标元素 -->
<button onClick="console.log(this)">123</button>
<!-- 事件自带一个 event 事件对象,可以传入 -->
<button onClick="console.log(event)">123</button>
event对象
弊端:
1、第一个问题是时机问题。
有可能 HTML 元素已经显示在页面上,用户都与其交互了,而事件处理程序的代码还无法执行。
如果函数在在按钮中代码的后面定义的,那么当用户在函数被定义之前点击按钮时,就会发生错误。
2、另一个问题是对事件处理程序作用域链的扩展(在表单中的按钮,可以直接访问表单中组件的值)在不同浏览器中可能导致不同的结果。
3、最后一个问题是 HTML 与 JavaScript 强耦合(关联性太强)。
如果需要修改事件处理程序,则必须在两个地方,即 HTML 和 JavaScript 中,修改代码。
这也是很多开发者不使用 HTML事件处理程序的主要原因。
方式2、元素的on属性监听
或者先获取元素,然后通过.属性添加
// ============== 1、先从文档中取得按钮 ==============
let btn = document.getElementById("myBtn");
// ==============2、给它的 onclick 事件处理程序赋值一个函数 ==============
btn.onclick = function() {
console.log("Clicked");
};
btn.onclick = function() { // 会覆盖上面的
console.log(this); // this指元素本身,就是btn
};
// ============== 3、移除事件 ==============
btn.onclick = null;
弊端:不够灵活,多次赋值事件会覆盖上面的,就像对一个属性多次赋值一样
方式3:EventTarget 的方法监听(推荐)
在JS的后续更新,所有DOM的元素,都是继承 EventTarget 这个对象,这个对象有3个处理事件的方法,因此所有的元素都可以被添加事件。
// ============== 1、先获取元素 ==============
let btn = document.getElementById("myBtn");
// ============== 2、再给元素添加事件 ==============
let handler = function() {
console.log(this.id);
};
btn.addEventListener("click", handler, false);
btn.addEventListener("click", ()=>{
console.log(this.id);
});
// ============== 3、移除事件 ==============
btn.removeEventListener("click", handler, false); // 有效果!
// 使用 addEventListener()添加的匿名函数(箭头函数)无法移除
btn.addEventListener("click", () => {
console.log(this.id);
}, false);
btn.removeEventListener("click", function() { // 没有效果!
console.log(this.id);
}, false);
可以添加多个,可以同时触发执行,多个事件处理程序以添加顺序来触发
有什么方法可以查看MDN文档:https://developer.mozilla.org/zh-CN/docs/Web/API/EventTarget
=============
事件流
说明
1、事件冒泡 Event Bubble
事件触发时,是由最内层的元素开始触发,然后一层一层触发。
/*
<!DOCTYPE html>
<html>
<head>
<title>Event Bubbling Example</title>
</head>
<body>
<div id="myDiv">Click Me</div>
</body>
</html>
*/
在点击页面中的
(1)
(2)
(3)
(4) document
现代浏览器中的事件会一直冒泡到 window 对象。
添加事件,默认就是事件冒泡。
2、事件捕获 Event Capture
和冒泡相反,事件捕获是由最外层开始触发,直到最里面那层
如果上面的例子使用事件捕获,则点击
(1) document
(2)
(3)
(4)
在事件捕获中,click 事件首先由 document 元素捕获,然后沿 DOM 树依次向下传播,直至到达实际的目标元素
添加事件时,第三个参数传true,就是事件捕获
3、DOM事件流
因此现代浏览器,两种情况都添加了,看你自己实际代码采取哪种,用的多的是事件冒泡
=============
事件对象 Event
说明
let btn = document.getElementById("myBtn");
// DOM 0
btn.onclick = function(event) {
console.log(event); // 见下
};
// DOM 2
btn.addEventListener("click", (event) => {
console.log(event); // 见下
}, false);
// HTML 事件
//<input type="button" value="Click Me" onclick="console.log(event)">
事件对象MDN文档:https://developer.mozilla.org/zh-CN/docs/Web/API/Event
事件类型 type见下
this
在事件处理程序内部,this 对象始终等于 currentTarget 的值,而 target 只包含事件的实际目标。
如果事件处理程序直接添加在了意图的目标,则 this、currentTarget 和 target 的值是一样的。
如果这个事件处理程序是添加到按钮的父节点(如 document.body)上,那么它们的值就不一样了。
// 在 document.body 上添加了单击处理程序
document.body.onclick = function(event) {
console.log(event.currentTarget === document.body); // true
console.log(this === document.body); // true
console.log(event.target === document.getElementById("myBtn")); // true
};
这种情况下点击按钮,this 和 currentTarget 都等于 document.body,这是因为它是注册事件处理程序的元素。
而 target 属性等于按钮本身,这是因为那才是 click 事件真正的目标。
由于按钮本身并没有注册事件处理程序,因此 click 事件冒泡到 document.body,从而触发了在它上面注册的处理程序。
阻止特定事件
preventDefault()方法用于阻止特定事件的默认动作。
比如,链接的默认行为就是在被单击时导航到 href 属性指定的 URL。
// 1、拿到要阻止的元素
let link = document.getElementById("myLink");
// 2、调用方法取消默认行为的事件
link.addEventListener("click",function(event) {
event.preventDefault(); // 阻止默认行为方法
})
阻止事件传播
stopPropagation()方法用于立即阻止事件流在 DOM 结构中传播,取消后续的事件捕获或冒泡。
// 1、拿到要阻止的元素
let btn = document.getElementById("myBtn");
// 2、阻止传播
btn.onclick = function(event) {
console.log("Clicked");
event.stopPropagation(); // 阻止了父组件的事件执行
};
// 父组件注册了事件,但由于被子元素阻止,不会执行
document.body.onclick = function(event) {
console.log("Body clicked"); // 不会执行
};
=============
事件类型
参考:https://developer.mozilla.org/zh-CN/docs/Web/Events
1、用户界面事件
用户界面事件或 UI 事件不一定跟用户操作有关。
load 加载
load 事件可能是 JavaScript 中最常用的事件。
window 对象
在 window 对象上,load 事件会在整个页面(包括所有外部资源如图片、JavaScript 文件和 CSS 文件)加载完成后触发。
一般来说,任何在 window 上发生的事件,都可以通过给元素上对应的属性赋值来指定,这是因为 HTML 中没有 window 元素。
img 对象
图片上也会触发load事件,包括DOM中的图片和非DOM中的图片。
<img src="smile.gif" onload="console.log('Image loaded.')">
let image = document.getElementById("myImage");
image.addEventListener("load", (event) => {
console.log(event.target.src);
});
使用新 Image 对象实现了图片预加载:
window.addEventListener("load", () => {
let image = new Image();
image.addEventListener("load", (event) => {
console.log("Image loaded!");
});
image.src = "smile.gif";
});
script 元素