原生JavaScript绑定事件监听器的几种方法
研读《JavaScript高级程序设计》笔记,在标注有删除线的部分是对原书内容的修正。由于书籍较早成书,在实际应用中使用这些方法时建议参考官方文档以确保准确性。
绑定事件监听器(事件处理程序)的方法有4种,第4种仅用于 IE8 及更低版本。
1.HTML事件处理程序(行内绑定)
具体实现方式包括对HTML元素设置相应的属性。这些属性的名称遵循on+事件名的命名规则,并将被赋值为能够执行的js代码。这些js代码将被解析并执行,在此过程中浏览器会整合到该功能并将元素属性封装成特定的数据格式以便后续操作。
<div onclick="alert('触发了点击事件')"> 点我试试 </div>
这种方式添加的事件处理程序会在事件冒泡阶段被处理;
事件对象(event)调用访问方法:是浏览器内部封装的一个局部变量;可以在事件处理流程中直接获取 event 对象;
<div onclick="console.log('我是事件对象', event);"> 点我试试 </div>
在该事件处理程序内部的 this 中心位置对应于该事件的目标元素,并由当前函数体内的代码逻辑将其与整个应用层架构中的相关组件进行绑定。
<div
onclick="
alert('事件冒泡到div容器');
console.log('事件目标元素是button:',event.target===document.getElementsByTagName('button')[0]); //true
console.log('this 是目标元素:',this===event.target); //false
console.log('当前事件处理程序绑定的元素是div:',event.currentTarget === document.getElementsByTagName('div')[0]); //true
console.log('this 是绑定当前事件处理程序的元素:',this===event.currentTarget); //true
"
>
<button type="button" onclick="alert('按钮被点击')" >点我试试</button>
</div>
unbind event的方法:由浏览器负责分配函数给元素上的相同名称属性;只需通过设置对应属性为 null 即可。
//以上面代码为例
<button
type="button"
onclick="alert('按钮被点击')" id="firstBtn"
>
点我试试
</button>
<button
type="button"
onclick="
document.getElementById('firstBtn').onclick = null;
alert('事件已删除');
"
>
点击该按钮删除前一个按钮的点击事件
</button>
该内部创建的函数还具有另一个特点:其主要特征是通过with语法实现对内部作用域的扩展
function(){
with(document) {
with(this.form) {
with(this) {}
}
}
}
PS:该事件绑定方法存在几个主要缺陷:当尚未满足执行条件时可能提前触发事件(如JS文件未加载),扩展事件处理程序的作用域链可能会因浏览器而异(例如,在访问某些对象属性时可能导致错误),导致HTML与JavaScript代码之间产生紧密联系。
2.DOM0 级事件处理程序(为元素属性赋值)
具体实现:将函数赋值给元素的事件处理程序属性;
<button type="button" id="myBtn">点我试试</button>
<script>
var btn = document.getElementById("myBtn");
btn.onclick = function() {
alert("按钮被点击");
};
</script>
这种方式添加的事件处理程序会在事件冒泡阶段被处理;
事件对象(event)的调用方法:事件对象可以在函数中作为第一个参数传递,并且也可以直接在函数体内获取 event 变量。
<button type="button" id="myBtn" >点我试试</button>
<script>
var btn = document.getElementById("myBtn");
btn.onclick = function (ev) {
console.log("事件对象:", ev);
console.log("事件对象:", event);
};
</script>
在eventHandler所在的函数体内使用this用于事件处理:由于将eventHandler赋值给某个HTML属性, 这相当于将该方法关联到那个特定对象上. 因此,在执行时它位于该对象的作用域内. 这里的this既是当前函数体内被引用的对象(即刚刚绑定的那个对象)也是与第一种绑定方式中的this保持一致.
解绑事件的方法:将对应事件处理程序的属性设置为 null 即可。
3.DOM2 级事件处理程序(addEventListener() 方法)
addEventListener() 文档
removeEventListener() 文档
具体实现:使用 addEventListener() 方法,接受3个参数(要处理的事件名、作为事件处理程序的函数、一个布尔值,这个布尔值为 true 表示在事件捕获阶段调用事件处理程序,为 false 则在事件冒泡阶段调用)。有些浏览器不支持事件捕获(如 IE8 及更低版本),所以谨慎绑定捕获阶段的事件监听器。
<button type="button" id="myBtn" >点我试试</button>
<script>
var btn = document.getElementById("myBtn");
btn.addEventListener('click', function () {
alert("在冒泡阶段触发了按钮的点击事件");
}, false);
</script>
事件对象(event)的方法:通过将 event 对象作为函数的第一个参数传递或在函数内部直接获取 event 变量的方式进行绑定(与前一种方法效果一致)。
<button type="button" id="myBtn" >点我试试</button>
<script>
var btn = document.getElementById("myBtn");
btn.addEventListener('click', function (ev) {
console.log("事件对象:", ev);
console.log("事件对象:", event);
}, false);
</script>
在事件处理程序内部使用的 this:这里注册的事件处理程序是在调用 addEventListener() 的作用域内触发的,在这种情况下这个 event handler 会由其对应的 HTML 元素进行引用。
解离事件的方式:可以通过元素调用removeEventListener()来实现移除操作;传入的参数与添加事件处理程序时相同;第二个参数(即事件处理程序函数)必须是同一个实例(指向地址一致),因此应将该函数存放在一个变量中;若传入的是匿名函数,则无法移除该事件监听器。
这种绑定方法的优势是可以注册多个事件处理程序。这些事件处理程序将按照注册顺序依次执行。
4.IE8 及更低版本的事件处理程序
通过detachEvent()方法可实现对事件目标的解绑功能,默认情况下不会在冒泡阶段触发相关事件处理程序。此方法允许同时绑定多个事件处理程序(如选中多个元素),但它们执行的顺序与绑定顺序相反。
<div>
<button type="button" id="myBtn">点我试试</button>
</div>
<script>
var btn = document.getElementById('myBtn');
btn.attachEvent('onclick', function () {
alert("触发了点击事件");
});
</script>
操作方式:事件对象可以通过作为第一个参数传递给函数来实现;此外,在函数内部可以直接获取 event 变量(该方法与之前的方法一致)。
<div>
<button type="button" id="myBtn">点我试试</button>
</div>
<script>
var btn = document.getElementById('myBtn');
btn.attachEvent('onclick', function (ev) {
console.log(ev);
console.log(event);
});
</script>
事件处理程序内部的 this:此处将要加入的事件处理程序将在全局作用域中运行,并与之前的方法不同。其对应的 this变量将指向window对象。
解绑或解除绑定的事件的方法:可以通过将指定元素作为目标来执行detachEvent()方法。所传递的参数与添加事件处理程序时所使用的参数相同。其中第二个参数即为事件处理函数对象,在此情况下两者必须是同一个实例且内存地址一致。因此为了确保能够正确地分离或解除绑定的事件监听器,在这种情况下需要将相关的 event handler 函数存储在一个变量中。
