一、事件的含义
JavaScript
事件是指在文档或者浏览器中发生的一些特定交互瞬间,比如打开某一个网页,浏览器加载完成后会触发load事件
,当鼠标悬浮于某一个元素上时会触发hover事件
,当鼠标点击某一个元素时会触发click事件
等等。
二、事件组成以及特点
事件由三部分组成
事件源 :给哪个元素/标签/节点来绑定事件
事件类型(某种状态) : 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、行内和属性绑定的解绑
行内解绑
<div class="box" onclick="null">hello</div>
属性绑定解绑
<div class="box">hello</div>
<script>
var box = document.querySelector('.box');
//绑定点击事件 属性要保存函数
box.onclick = function(){
console.log(6666);
}
//解绑 不让你保存函数,不就是解绑了么
box.onclick = null; //false也可以
</script>
4.2、事件监听器的解绑
注意!!!这里的绑定和解绑的函数一定是同一个
<body>
<div id="xiake">下课</div>
<script>
var xiake = document.querySelector("#xiake");
function fn1() {
console.log("fn1执行");
}
//给xiake元素添加一个监听事件
xiake.addEventListener("click", fn1);
//移除对应的元素的对应的监听程序
xiake.removeEventListener("click", fn1);
</script>
</body>
4.3、事件解绑的应用
抢红包
抢红包时,一旦点击了抢红包按钮,函数正常运行,就会连接后台,会很卡,因为突然很多人在抢(点的那一刻,大家都在同一台服务器发送网络请求),此时就点不动(如果还能点动,函数又运行,更卡,所以不合理),抢红包的按钮就只按一下,运行了就不能点了。所以怎么实现函数运行(一点击),就不能再点击(运行了)?解绑就可以了。
<body>
<div class="box">抢红包</div>
<script>
var box = document.querySelector(".box");
//绑定点击事件 属性要保存函数
box.onclick = function () {
box.onclick = null;
console.log('红包已经点击,再次点击无效');
};
</script>
</body>
五、事件的冒泡和捕获
5.1、什么是事件捕获和事件冒泡
事件冒泡
如果一个元素的事件被触发,那么他的所有父级元素的同名事件也会被依次触发
元素->父元素->body->html->document->window
事件冒泡一直存在,只不过以前我们没有给父级元素加同名事件
事件捕获
从最顶级的父元素一级一级往下找子元素触发同名事件,直到触发事件的元素为止
事件捕获,只能通过addEventListener
并且参数写true
才是事件捕获
其他都是冒泡(不是通过addEventListener
添加、addEventListener
参数为false
)
5.2、事件流
事件流分为三个阶段
1.捕获阶段
2.目标阶段
3.冒泡阶段。
5.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
有多少,更新多频繁,我们只需要维护一个函数就够了。
六、事件对象
6.1、什么是事件对象
当事件被触发时(如onclick事件),浏览器会自动创建一个名为
event
的JavaScript
对象,这个对象存在于window
对象中。window.event(window可以省略)
表示当前正在处理的事件的详细信息(如事件类型(click、mousemove
等)、目标元素、鼠标位置、按键状态等)。
6.2、事件对象的作用
事件对象可以用于访问事件的类型、目标元素、鼠标位置、按键状态等信息,以及阻止事件的默认行为或停止事件的传播。
6.3、如何获取事件对象
6.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>
6.3.2、属性绑定事件获取事件对象
在属性绑定事件的方式中,浏览器会将事件对象
event
传递给事件处理函数(handler
)
// 获取页面中id为box的元素
var box = document.getElementById("box");
box.onclick = function (event) {
//event就是事件触发的时候浏览器传递给事件处理函数
console.log(event);
};
6.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
可以获取事件的目标元素。
6.4、事件对象阻止默认行为
有些事件具有默认行为,例如单击链接将导航到链接的
URL
,按下回车键将提交表单等。在某些情况下,我们可能需要取消事件的默认行为。可以使用事件对象的preventDefault()
方法来阻止事件的默认行为。
const myLink = document.querySelector('#my-link');
myLink.addEventListener('click', function(event) {
event.preventDefault(); // 阻止单击链接的默认行为
});
6.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!
。
6.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 | 当窗口大小改变时触发此事件。 |
7.1、onfocus获得焦点和onblur失去焦点事件
当焦点进入网页上的username文本输入框,该输入框的背景色变为绿色,当焦点离开,背景色改为白色。
<form name="myform">
username:<input
type="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>
7.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处理:
<form
name="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>
7.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";
else
document.bgColor="white";
isRed=!isRed; // isRed变量的值取反
}
</script>
7.4、onmouseover鼠标移入和onmouseout鼠标移出事件
当用户在网页上把鼠标移入某个元素的区域,会触发onmouseover事件,把鼠标移出某个元素的区域,会触发onmouseout事件。鼠标移入该图片区域,图片的透明度设为1,当鼠标移出该图片区域,透明度设为0.3
<img
src="logo.gif"
onmouseover="visible(this,1)"
onmouseout="visible(this,0.3)"
/>
<script>
function visible(element, n) {
// 设置图片的透明度
element.style.opacity = n;
}
</script>
7.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>
7.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>
7.7、onscroll事件
onscroll 事件在元素的滚动条被滚动时发生。
- 在滚动
<div>
元素时执行 JavaScript:
<div onscroll="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);
7.8、onresize事件
onresize 事件在浏览器窗口被调整大小时发生。
- 调整浏览器窗口大小时执行 JavaScript:
<body onresize="myFunction()">
- 属性绑定
object.onresize = function(){myScript};
- 使用 addEventListener() 方法在 window 对象上附加 “resize” 事件:
window.addEventListener("resize", myFunction);