一、事件的含义
JavaScript事件是指在文档或者浏览器中发生的一些特定交互瞬间,比如打开某一个网页,浏览器加载完成后会触发load事件,当鼠标悬浮于某一个元素上时会触发hover事件,当鼠标点击某一个元素时会触发click事件等等。
三种事件模型
DOM0 级事件模型,这种模型不会传播,所以没有事件流的概念,但是现在有的浏览器支持以冒泡的方式实现,它可以在网页中直接定义监听函数,也可以通过 js 属性来指定监听函数。所有浏览器都兼容这种方式。
直接在 dom 对象上注册事件名称,就是 DOM0 写法。IE 事件模型,在该事件模型中,一次事件共有两个过程,事件处理阶段和事件冒泡阶段。
事件处理阶段会首先执行目标元素绑定的监听事件。
然后是事件冒泡阶段,冒泡指的是事件从目标元素冒泡到document,依次检查经过的节点是否绑定了事件监听函数,如果有则执行。
attachEvent就是IE事件模型 ,attachEvent用来添加监听函数,可以添加多个监听函数,会按顺序依次执行。DOM2 级事件模型,在该事件模型中,一次事件共有三个过程,
第一个过程是事件捕获阶段。捕获指的是事件从 document 一直向下传播到目标元素,依次检查经过的节点是否绑定了事件监听函数,如果有则执行。后面两个阶段和 IE 事件模型的两个阶段相同。
addEventListener 就是DOM2级事件模型。
二、事件组成以及特点
事件由三部分组成
事件源 :给哪个元素/标签/节点来绑定事件
事件类型(某种状态) : eg:点击状态
事件处理程序(事件句柄:handler)
事件函数的特点
全小写、以on开头+事件名,如onclick
三、事件的绑定方式
3.1、行内式
<div class="box" onclick="console.log(66666)">hello</div>
注意: 行内绑定事件,事件直接执行引号内的代码,这就意味着如下方式绑定事件将不会触发方法
<div id="container"><button id="btn2" onclick="test">test2</button>
</div>
<script>function test() { }
</script>
3.2、属性绑定
只能绑定一个处理程序handler,如果绑定多个,只有最后一个生效
<div class="box">hello</div><script>var box = document.querySelector('.box'); //对象添加属性 点语法 box.onclick = function(){console.log('你购买了装备');}box.onclick = function(){console.log('你购买了装备2');}</script>
3.3、给元素添加一个事件监听器(推荐)
3.3.1、addEventListener介绍
addEventListener() 方法用于向指定元素添加事件处理程序(事件句柄handler)。
参数1:事件名称必须。字符串,指定事件名。
注意: 不要使用 “on” 前缀。 例如,使用 click ,而不是使用 onclick。参数2:function 必须。指定要事件触发时执行的函数。
注意:事件对象会作为第一个参数传入函数。参数3:useCapture 可选。布尔值,指定事件是否在捕获或冒泡阶段执行。
true - 事件处理程序(事件句柄)在捕获阶段执行
false默认。事件处理程序(事件句柄)在冒泡阶段执行
事件对象的类型取决于特定的事件。例如, click事件属于 MouseEvent(鼠标事件) 对象。
3.3.2、addEventListener给元素绑定事件
var box = document.querySelector('.box');
//给元素添加一个事件监听器 (绑定事件处理程序)
box.addEventListener('click',function(){console.log(666);
});
console.log(999);
优点一
不阻断代码
分析:还没点击,就打印出999,点击后打印出666,说明 addEventListener()函数并不阻断代码执行。
优点二可以绑定多个handler,且不影响行内绑定的
<body> <style>.box{width: 200px;height: 200px;background-color: #bfa;}</style><div class="box">hello</div><script>var box = document.querySelector('.box'); //给元素添加一个事件监听器 (绑定事件处理程序) box.addEventListener('click',function(){console.log(6661);});box.addEventListener('click',function(){console.log(6662);});</script>
</body>
分析:一点击按钮,就会打印出 6661 和 6662
四、事件的冒泡和捕获
4.1、什么是事件捕获和事件冒泡
事件冒泡
如果一个元素的事件被触发,那么他的所有父级元素的同名事件也会被依次触发
元素->父元素->body->html->document->window
事件冒泡一直存在,只不过以前我们没有给父级元素加同名事件
事件捕获
从最顶级的父元素一级一级往下找子元素触发同名事件,直到触发事件的元素为止
事件捕获,只能通过addEventListener并且参数写true才是事件捕获
其他都是冒泡(不是通过addEventListener添加、addEventListener参数为false)
4.2、事件流
事件流分为三个阶段
1.捕获阶段
2.目标阶段
3.冒泡阶段。
4.3、绑定捕获和冒泡事件
JavaScript中,我们可以使用addEventListener方法来绑定捕获和冒泡事件。
element.addEventListener(event, function, useCapture);
其中,event表示要绑定的事件类型,function表示事件触发时要执行的函数,useCapture是一个可选的参数,用于指定事件是使用捕获还是冒泡阶段进行处理。
当useCapture为false或未提供时,事件将在冒泡阶段进行处理;当useCapture为true时,事件将在捕获阶段进行处理此时事件不在冒泡,只捕获不冒泡。
<div id="blueBox"><div id="yellowBox"><div id="greenBox"></div></div>
</div><script> let blueBox = document.getElementById('blueBox');let yellowBox = document.getElementById('yellowBox');let greenBox = document.getElementById('greenBox');blueBox.addEventListener('click', () => {console.log('blueBox')})yellowBox.addEventListener('click', () => {console.log('yellowBox')})greenBox.addEventListener('click', () => {console.log('greenBox');})
</script>
当点击绿色方块时,输出greenBox、yellowBox、blueBox,因为绿色包含在黄色里,黄色和绿色被包含蓝色中。addEventListener不写第三个参数时,事件将在冒泡阶段进行处理,从目标元素开始,逐级向外层元素传播,直到达到最外层的元素,也就是绿色、黄色、蓝色。
同理,点击黄色时,输出yellowBox、blueBox。点击蓝色时,输出blueBox。
如果将第三个参数全部设成true,点击绿色(greenBox),将输出blueBox、yellowBox、greenBox,因为事件将在捕获阶段进行处理,事件捕获的顺序是从最外层的元素开始,逐级向内部元素传播,直到达到目标元素,也就是蓝色、黄色、绿色。
5.4、阻止事件冒泡
event.stopPropagation()
调用该方法会阻止事件继续传播,但不会阻止其他事件处理程序被触发。也就是说,如果一个元素上绑定了多个事件处理程序,调用该方法只会阻止事件传播到更高层级的元素,而不会阻止同一元素上的其他事件处理程序被触发。
blueBox.addEventListener('click', () => {console.log('blueBox')}, true);yellowBox.addEventListener('click', () => {console.log('yellowBox')})greenBox.addEventListener('click', (event) => {console.log('greenBox');event.stopPropagation();}, true);
在上面的示例中,当点击绿色方块时,调用event.stopPropagation()会阻止事件继续传播到外层元素,所以只会输出"greenBox",而不会输出”yellowBox”和”blueBox”。
5.5、事件委托
事件委托也称为事件代理(Event Delegation),事件委托是一种将事件处理程序绑定到一个父元素上,而不是将事件处理程序绑定到每个子元素上的技术。通过事件委托,可以减少事件处理程序的数量,提高性能和代码的可维护性。
<ul id="ul"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li>
</ul><script>let li = document.getElementsByTagName("li");for (let i = 0; i < li.length; i++) {li[i].addEventListener("click", () => {console.log(li[i].innerHTML);});}
</script>
如上述代码所示,点击某一数字,就会输出对应内容。节点少的时候还好,如果节点多达上千上万个,就需要声明相当多的事件函数,比较消耗内存。而且如果列表经常发生动态变更,也会导致大量监听事件的移除和绑定。
在这种情况下,事件委托就可以体现它的优势了。事件委托正是利用事件流的冒泡特性,将本来要绑定到多个元素的事件函数,委托到了其祖先元素上。
优点:节约内存 提升性能(不需要注销子节点)
//事件代理 节约内存 提升性能(不需要注销子节点)
let ul = document.getElementById("ul");
ul.addEventListener("click", (event) => {console.log(event.target.innerHTML);
})
我们通过将事件处理程序绑定到父元素ul上,当点击列表项时,通过 event 对象拿到必要的信息,会打印出被点击的列表项的内容。如此这般,不管li有多少,更新多频繁,我们只需要维护一个函数就够了。
五、事件对象
5.1、什么是事件对象
当事件被触发时(如onclick事件),浏览器会自动创建一个名为event的JavaScript对象,这个对象存在于window对象中。window.event(window可以省略)表示当前正在处理的事件的详细信息(如事件类型(click、mousemove等)、目标元素、鼠标位置、按键状态等)。
5.2、事件对象的作用
事件对象可以用于访问事件的类型、目标元素、鼠标位置、按键状态等信息,以及阻止事件的默认行为或停止事件的传播。
5.3、如何获取事件对象
5.3.1、行内式绑定事件获取事件对象
//事件被触发后,event对象被创建在window上,window可以省略
<div id="box" onclick="doClick()"></div>
<script>function doClick() {console.log(window.event);}
</script>
注意!!!!
doClick()这里的括号不可省略,这是因为内联模式下,事件直接执行引号内的代码。
以下方式方法不能调用doClick
<div id="box" onclick="doClick"></div>
<script>function doClick() {console.log(window.event);}
</script>
5.3.2、属性绑定事件获取事件对象
在属性绑定事件的方式中,浏览器会将事件对象event传递给事件处理函数(handler)
// 获取页面中id为box的元素var box = document.getElementById("box");box.onclick = function (event) {//event就是事件触发的时候浏览器传递给事件处理函数console.log(event);};
5.3.3、addEventListener绑定事件获取事件对象
// 给一个按钮添加点击事件处理程序
const myButton = document.querySelector("#my-button");myButton.addEventListener("click", function (event) {console.log(event.type); // 获取事件类型(click)console.log(event.target); // 获取目标元素(myButton)
});
在上面的代码中,当按钮被单击时,浏览器将自动创建一个事件对象event,并将其传递给事件监听器函数的第二个参数。我们可以通过访问event对象的属性来获取有关事件的信息。
例如,使用event.type可以获取事件类型,而使用event.target可以获取事件的目标元素。
5.4、事件对象阻止默认行为
有些事件具有默认行为,例如单击链接将导航到链接的URL,按下回车键将提交表单等。在某些情况下,我们可能需要取消事件的默认行为。可以使用事件对象的preventDefault()方法来阻止事件的默认行为。
const myLink = document.querySelector('#my-link');
myLink.addEventListener('click', function(event) {event.preventDefault(); // 阻止单击链接的默认行为
});
5.5、事件对象停止事件传播
在JavaScript中,事件通常会在DOM树中沿着从子元素到祖先元素的路径进行传播(冒泡)。这意味着,当您单击一个<button>元素时,该按钮的父级元素也会收到单击事件。
在某些情况下,您可能需要仅响应事件的特定元素,而取消事件对其祖先元素的进一步传播。可以使用事件对象的stopPropagation()方法来停止事件传播。
const container = document.querySelector('#my-container');
container.addEventListener('click', function(event) {console.log('Clicked the container!');
});const myButton = document.querySelector('#my-button');
myButton.addEventListener('click', function(event) {event.stopPropagation(); // 阻止事件传播到父元素console.log('Clicked the button!');
});
在上述代码中,我们用stopPropagation()方法阻止了事件传播到容器元素,因此单击按钮时,只会显示Clicked the button!而不会显示Clicked the container!。
5.6、事件对象的属性和方法总结
JavaScript中的事件对象是一个非常有用的工具,可以在事件处理程序中访问和操作许多方面的事件信息。下面是常用的事件对象属性和方法的总结:
event.type - 获取事件类型(例如,“click”、"mousedown"等)。
event.target - 获取目标元素(即发出事件的元素)。
event.preventDefault() - 取消事件的默认行为。
event.stopPropagation() - 停止事件在DOM树中的传播。
event.clientX和event.clientY - 获取鼠标光标的坐标。
event.keyCode - 获取按下的键的键码。
总之,了解事件对象的相关属性和方法可以帮助我们更好地理解和操作JavaScript中的事件。我们可以根据需要使用它们来执行特定的操作,并确保一个可交互的和响应式的用户体验。
六、JavaScrip脚本可以处理的事件
事件类型 | 事件 | 说明 |
表单相关 | onfocus | 当某个元素获得焦点时触发此事件. |
表单相关 | onblur | 当某个元素失去焦点时触发此事件。 |
表单相关 | onchange | 当某个元素失去焦点并且元素的内容发生改变时触发此事件。 |
表单相关 | onsubmit | 提交表单时触发此事件。 |
表单相关 | onreset | 表单被重置时触发此事件 |
鼠标相关 | onclick | 单击鼠标时触发此事件 |
鼠标相关 | ondblclick | 双击鼠标时触发此事件。 |
鼠标相关 | onmousedown | 按下鼠标时触发此事件。 |
鼠标相关 | onmouseup | 按下鼠标后松开鼠标时触发此事件。 |
鼠标相关 | onmouseover | 当鼠标移动到某元素的区域时触发此事件。 |
鼠标相关 | onmousemove | 当鼠标在某元素的区域内移动时触发此事件。 |
鼠标相关 | onmouseout | 当鼠标离开某元素的区域时触发此事件。 |
键盘相关 | onkeypress | 键盘上的键被按下并释放时触发此事件。可处理单键的操作。 |
键盘相关 | onkeydown | 键盘上的键被按下时触发此事件。可处理单键或组合键的操作。 |
键盘相关 | onkeyup | 键盘上的键被按下后松开时触发此事件。可处理单键或组合键的操作 |
页面相关事件 | onload | 当页面完成加载时触发此事件。 |
页面相关事件 | onunload | 当离开页面时触发此事件。 |
页面相关事件 | onresize | 当窗口大小改变时触发此事件。 |
6.1、onfocus获得焦点和onblur失去焦点事件
当焦点进入网页上的username文本输入框,该输入框的背景色变为绿色,当焦点离开,背景色改为白色。
<form name="myform">username:<inputtype="text"name="username"onfocus="dofocus()"onblur="doblur()"/>
</form><script>function dofocus() {// 获得当前的事件var event = window.event;// 获得触发当前事件的元素var element = event.srcElement;// 把元素的背景色改为绿色element.style.background = "#00FF00";}function doblur() {// 获得当前的事件var event = window.event;// 获得触发当前事件的元素var element = event.srcElement;// 把元素的背景色改为白色element.style.background = "#FFFFFF";}
</script>
6.2. onsubmit表单提交和onreset表单重置事件
当用户按下表单中的提交按钮,会触发onsubmit事件,按下重置按钮,会触发onreset事件。 以下输入框的type属性的值分别为submit和reset,分别表示提交按钮和重置按钮:
<input type="submit" value="submit" />
<input type="reset" value="reset" />
以下代码指定dosubmit()函数处理onsubmit事件,doreset()函数处理onreset事件,action属性指定把表单提交给后端的hello.jsp处理:
<formname="myform"onsubmit="return dosubmit()"onreset="doreset()"action="hello.jsp"
></form>
完整代码
<form name="myform" action="hello.jsp" onsubmit="return dosubmit()">username:<input type="text" name="username" /><input type="submit" value="submit" /><input type="reset" value="reset" />
</form><script>function dosubmit() {var isSubmit = true;if (myform.username.value == "") {alert("Please input username.");isSubmit = false;}return isSubmit;}
</script>
6.3、onclick鼠标单击事件
当用户单击网页上的按钮、图片等元素,会触发onclick事件。 例程4的bgcolor.html会在网页上显示一个change按钮,点击该按钮,网页的背景色会在红色与白色之间切换。document.bgColor表示网页的背景色。
<form name="myform" ><input type="button" value="change" onclick="doclick()" />
</form><script>
var isRed=true;function doclick(){ // 切换网页的背景色if(isRed)document.bgColor="red";elsedocument.bgColor="white";isRed=!isRed; // isRed变量的值取反
}
</script>
6.4、onmouseover鼠标移入和onmouseout鼠标移出事件
当用户在网页上把鼠标移入某个元素的区域,会触发onmouseover事件,把鼠标移出某个元素的区域,会触发onmouseout事件。鼠标移入该图片区域,图片的透明度设为1,当鼠标移出该图片区域,透明度设为0.3
<imgsrc="logo.gif"onmouseover="visible(this,1)"onmouseout="visible(this,0.3)"
/><script>function visible(element, n) {// 设置图片的透明度element.style.opacity = n;}
</script>
6.5. onkeydown、onkeypress、onkeyup按键事件
onkeypress
这个事件在用户按下并放开任何字母数字键时发生,并不是每个按键都会触发这个事件。系统按钮(例如:箭头键和功能键)无法得到识别。
onkeyup
这个事件在用户放开任何先前按下的键盘键时发生。
onkeydown
这个事件在用户按下任何键盘键(包括系统按钮,如箭头键和功能键)时发生。
最难理解的是 onkeyup 和 onkeypress 事件,onkeypress按下并放开,onkeyup 按下并放开所有键,其中略有不同,对于输入快的人,按键都是连续的,所以 onkeypress每个按键都会调用,可理解为正在输入的状态中调用,但是 onkeyup是所有按键都弹起时被调用,调用的次数是按键的个数。
onkeydown 事件最先执行,其次是 onkeypress,最后是才是 onkeyup
三个事件同时在的话,onkeyup不会在中途执行,也就是要等所有按键都弹起以后才会执行。
onkeydown案例
一个红色的色块,当按下键盘的LEFT、RIGHT、UP、DOWN键,色块就会向相应的方向移动
<div id="box"></div><script>
// 获取页面中id为box的元素
var box = document.getElementById("box");
box.style.position = "absolute"; // 色块绝对定位
box.style.width = "20px"; // 色块宽度
box.style.height = "20px"; // 色块高度
box.style.backgroundColor = "red"; // 色块背景色// 指定处理onkeydown事件的函数
document.onkeydown = dokeydown;// 方向键控制色块移动
function dokeydown(){ var event = window.event; switch(event.keyCode){ // 获取当前按下键盘键的编码case 37 : // 按下LEFT箭头键,向左移动5个像素box.style.left = box.offsetLeft - 5 + "px";break;case 39 : // 按下RIGHT箭头键,向右移动5个像素box.style.left = box.offsetLeft + 5 + "px";break;case 38 : // 按下UP箭头键,向上移动5个像素box.style.top = box.offsetTop - 5 + "px";break;case 40 : // 按下DOWN箭头键,向下移动5个像素box.style.top = box.offsetTop + 5 + "px";break;}
}
</script>
6.6. onload页面加载和onunload页面卸载事件
当用户访问某个网页,浏览器就会先加载该网页,此时会触发onload事件。当用户离开网页、刷新网页或关闭浏览器时,会触发onunload事件。
有时候我们需要在dom渲染完成的时候,才能获取dom,这个时候就可以使用onload事件
<script>const boxDom = document.getElementById("box"); // 报错--此时dom并未渲染完成// 正确写法window.onload = function () {const boxDom = document.getElementById("box");};
</script>
<body><div id="box"></div>
</body>
6.7、onscroll事件
onscroll 事件在元素的滚动条被滚动时发生。
在滚动 <div> 元素时执行 JavaScript:
<div οnscrοll="myFunction()">
在不同滚动位置的类名之间切换 - 当用户从页面顶部向下滚动 50 像素时,类名 “test” 将被添加到元素中(再次向上滚动时将被删除)。
window.onscroll = function() {myFunction()};function myFunction() {if (document.body.scrollTop > 50 || document.documentElement.scrollTop > 50) {document.getElementById("myP").className = "test";} else {document.getElementById("myP").className = "";}
}
使用 addEventListener() 方法:
object.addEventListener("scroll", myScript);
6.8、onscroll事件
onresize 事件在浏览器窗口被调整大小时发生。
调整浏览器窗口大小时执行 JavaScript:
<body οnresize="myFunction()">
属性绑定
object.onresize = function(){myScript};
使用 addEventListener() 方法在 window 对象上附加 “resize” 事件:
window.addEventListener("resize", myFunction);