复习:事件:当(某个)按钮 被 点击 时,弹出提示框……
再次演示时注意强调JavaScript代码的位置。因为浏览器对HTML文档的解析是从上往下依次执行的,所以JavaScript代码运行的时候一定要确保相应的DOM元素已经被浏览器解析。
深入学习事件,首先要了解一些基本概念:
事件本身也不是JavaScript语言的一部分,而是由浏览器提供的接口和底层支持。只是JavaScript可以调用这些事件而已,但是因为事件的应用如此广泛,我们有时候又说“JavaScript(编程)是事件驱动的”……
如前所示。
如果代码非常简单且不要求重用的话,可以直接使用JavaScript的源代码:
<h1 onclick="alert(`先学习后付费`)">源栈欢迎您!</h1>
一般认为(但不绝对)这种行内的写法不好,因为这样就(同HTML与CSS的混杂一样)把HTML内容(呈现)和JavaScript(实现)混在一起了,没有满足“隔离原则”,所以应该在:
中,完成事件绑定。具体又分为两种:
document.getElementsByTagName('h1')[0].onclick = welcome; //注意这里不能带圆括号和参数
看起来和在HTML元素中添加属性差不多,一样可以直接使用匿名函数。
注意:
按W3C推荐,应首先使用addEventListener(type, listener[, options])
document.getElementsByTagName('h1')[0].addEventListener('click', greet);
这里的事件类型又没有on的前缀了,(有的IDE)也没有智能提示,而且是大小写敏感的……折腾啊,o(╥﹏╥)o
用JavaScript代码绑定的事件,可以在浏览器上F12查看。
演示:先找到DOM元素,然后
document.getElementsByTagName('h1')[0].click();
这和用户用鼠标点击h1元素产生相同的效果,即h1上绑定的onclick事件回调函数会被触发。
如果说“注册”,对应的是“退订”。
有两种方式:
document.getElementsByTagName('h1')[0].removeEventListener("click", welcome)必须是两个参数,即需要指定解除某事件的哪一个handler。
document.getElementsByTagName('h1')[0].onclick = null;
主要还是看老大的喜好。
另:addEventListener()在事件冒泡中还有一些特殊性。
当我们在
中绑定事件时:
在事件调用函数中可使用 this 指向事件源,即:触发事件的DOM/BOM对象。
使用this,可以简化代码。比如,我们要点击切换颜色:
document.getElementsByTagName('h1')[0].addEventListener("click", function(){ this.style.color = "blue"; });同时,事件调用函数可以带一个event参数(但IE中有全局变量window.event):
document.getElementsByTagName('a')[0].addEventListener("click", function(event){
event.target === this //true,触发事件的DOM元素 event.type // "click"
event.preventDefault(); //组织DOM元素默认的行为
不一样:
<a onclick="welcome(event)" > 源栈欢迎您!</a> //对应接收 function welcome(e){此时可以使用event.target做this用
event.target.style.color = "red";
<a onclick="welcome(this)" > 源栈欢迎您!</a>
function welcome(element){ element.style.color = "red";但在(现代浏览器中的)回调函数中仍能使用event,这时候的event是window的属性。
一般的事件处理不需要考虑这种情况。但是,这不仅是一个常见面试题,而且有其实际使用场景。
<div id="propagate"> <p> 源栈欢迎您 </p> </div>为了便于演示,加上一点CSS效果:
<style> #propagate { padding: 30px; border: 1px solid; } #propagate > p { background-color: blue; border: 1px dashed; } </style>
let father = document.getElementById('propagate'), child = father.children[0]; father.addEventListener('click', function () { console.log('event handler on father'); }); child.addEventListener('click', function () { console.log('event handler on child'); });
@想一想@:
浏览器大战(复习)的年代,不同的浏览器使用了不同的机制来处理这种场景
现代浏览器都按W3C标准进行了统一。
当事件行为发生时,有两个“传播”阶段:首先由外向内“捕获”,然后再从内向外“冒泡”,如下图所示。
那为什么上述演示的结果感觉是只有“冒泡”呢?
因为我们在绑定事件时(默认)指明了:该事件处理程序只适用/响应于冒泡阶段。
addEventListener()还有第三个参数useCapture,当其为
演示:
father.addEventListener('click', function () { console.log('event handler on father'); }, true); child.addEventListener('click', function () { console.log('event handler on child'); }, true);以及:父true子false,父false子true
#理解#:上述(由浏览器控制的)①②③④四个阶段始终是存在的,我们能控制的是:事件处理程序(handler)在哪一个阶段(phase)予以响应。
可以想象,事件冒泡/捕获机制极有可能会带来混乱,所以有时候我们需要:阻止事件(行为)继续传递,这就可以调用:
event.stopPropagation();
注意:propagation包含冒泡和捕获
演示:采用冒泡/捕获,在父子元素事件handler中添加stopPropagation()
#常见面试题#
问:stopPropagation()和preventDefault()的区别?
现在我们来看一个真实的适用场景:给一个父元素(div)里面的所有子元素(p)绑定click事件。
<div id="propagate"> <p> 源栈欢迎您 </p> <p> 大神小班 </p> <p> 灵活学制 </p> </div>
利用冒泡机制,我们就不需要在每一个p标签上添加事件了:
for (let i = 0; i < father.length; i++) { father[i].onmouseover = function(){ console.log(this.innerText); }; }
而是在div上绑定事件。
但是,click事件处理程序中要求显示用户所点击DOM元素的文本,怎么办?@想一想@:能不能用this?
实际上,这里面可以使用的有三个对象:
father.addEventListener('click', function (event) { console.log('this === event.target:' + (this === event.target)); console.log('event.target:' + event.target.innerHTML); //符合题意需求 console.log('this === event.currentTarget:' + (this === event.currentTarget)); console.log('event.currentTarget:' + event.currentTarget); });@试一试@:当在父子元素上都绑定了事件之后,又各自使用冒泡/捕获,会是一种什么情形?
本章作业名为:event.html
多快好省!前端后端,线上线下,名师精讲
更多了解 加: