JavaScript自定义事件
1. 引言
在Web中,事件,通常是指某个动作的完成,比如,鼠标点击、鼠标移动、键盘按下等
事件监听,通常是指监听某个动作,动作完成后触发相应的变化,如,鼠标点击按钮后弹出确认框
通过事件监听,当某个事件完成或者状态改变时,可以触发监听者的更新或预设行为,比如,点击按钮弹出确认框、窗口大小改变时网页内容也改变大小等
在软件工程中,这种设计模式叫观察者模式,它定义了一种一对多的依赖关系,当一个对象的状态发生改变时,其所有依赖者都会收到通知并自动更新
2. 内置事件
在Web中,事件的主体(即,可以触发与监听事件的对象)通常是DOM对象,如,Button、Div等
2.1 事件监听
事件监听是主要的应用场景
HTML和JS已经内置了大部分会出现的事件,经典的事件如点击事件,通常Button可以这样监听:
<body>
<button>按钮</button>
<script>
var btn = document.querySelector('button');
btn.onclick = function() {
console.log('click');
}
</script>
</body>
即设置on+<event name>
属性的方式,设置对事件的监听
现在通常使用下面的方式实现监听:
<body>
<button>按钮</button>
<script>
var btn = document.querySelector('button');
btn.addEventListener('click', function() {
console.log('click');
});
</script>
</body>
浏览器中实现的详细的事件,可以从MDN中查询:Event - Web API 接口参考 | MDN (mozilla.org)
2.2 事件触发
通常事件触发是行为触发的,比如,鼠标去点击按钮触发
有时需要通过代码去主动触发,如何实现代码主动触发事件呢
经典的事件,通常DOM对象内置了主动触发的方法,如点击事件:
<body>
<button>按钮</button>
<script>
var btn = document.querySelector('button');
btn.addEventListener('click', function() {
console.log('click');
});
btn.click(); // 触发点击事件
</script>
</body>
如果DOM对象没有内置了主动触发的方法,可以使用下面这种方式:
<body>
<button>按钮</button>
<script>
var btn = document.querySelector('button');
btn.addEventListener('click', function() {
console.log('click');
});
btn.dispatchEvent(new Event('click')); // 触发click事件
</script>
</body>
3. 自定义事件
3.1 DOM对象
上述事件是浏览器内置所支持的,加入浏览器没有支持或者想自定义事件呢,比如,想监听数据加载,加载完成后对应的DOM元素刷新
这时可以设置一个名为dataLoaded
的自定义事件(Custom Event),将DOM元素设置为监听者,然后加载数据后触发事件:
<body>
<div id="containter"></div>
<script>
const container = document.getElementById('containter');
container.addEventListener('dataLoaded', (e) => {
console.log(e.detail);
container.innerHTML = `<h1>${e.detail.name}</h1><p>${e.detail.age}</p>`
})
function load() {
// 模拟数据加载
const data = {
name: 'John',
age: 20
}
const event = new CustomEvent('dataLoaded', {
detail: data
})
container.dispatchEvent(event); // 触发dataLoaded事件
}
load();
</script>
</body>
CustomEvent的详细介绍可以参考:CustomEvent() - Web API 接口参考 | MDN (mozilla.org)
上述代码中,看上去这个事件机制用法是多余的,完全可以在加载数据后执行相应的更新函数即可,何必再套一层事件监听与事件触发呢
倒也不然,如下面这个例子,有三个文件,分别是index.html
,index.js
,request.js
index.html:
<body>
<div id="containter"></div>
<script>
const container = document.getElementById('containter');
container.addEventListener('dataLoaded', (e) => {
console.log(e.detail);
container.innerHTML = `<h1>${e.detail.name}</h1><p>${e.detail.age}</p>`
})
</script>
</body>
index.js:
const container = document.getElementById('containter');
container.addEventListener('dataLoaded', (e) => {
doSomething()
})
function doSomething(){
// ...
}
request.js:
function load() {
// 模拟数据加载
const data = {
name: 'John',
age: 20
}
const event = new CustomEvent('dataLoaded', {
detail: data
})
container.dispatchEvent(event);
}
load();
上述示例中,在数据加载后,其余各处会执行相应的函数,代码组织也更为易懂
3.2 JS对象
上面所述的均为DOM对象,JS中的对象能否监听事件呢
答曰,可以,需要继承EventTarget
EventTarget
详细的API介绍可以参考MDN:EventTarget - Web API 接口参考 | MDN (mozilla.org)
下面是一个示例代码,展示了如何编写一个类,继承自EventTarget
,并实现事件监听功能:
class MyObject extends EventTarget {
myMethod() {
// 在方法内部触发事件
this.dispatchEvent(new Event('myEvent'));
}
}
// 实例化对象
const obj = new MyObject();
// 添加事件监听器
obj.addEventListener('myEvent', myEventHandler);
// 事件处理函数
function myEventHandler(event) {
// 处理事件的逻辑
console.log('Event triggered:', event);
}
// 调用方法,触发事件
obj.myMethod();