Web页面需要经常和用户之间进行交互,而交互的过程中我们可能想要捕捉这个交互的过程:
用户点击了某个按钮
、用户在输入框里面输入了某个文本
、用户鼠标经过了某个位置
;JavaScript代码和事件之间的桥梁
;响应
(执行某个函数),所以我们需要针对事件编写处理程序
(handler);如何进行事件监听呢?
script
中直接监听(很少使用);on
来监听事件;addEventListener
来监听;<body>
<!-- 监听方式一 script-->
<button onclick="alert('hello world');">nihao1</button>
<button>nihao2</button>
<button>nihao3</button>
<script>
// 监听方式二 on
var btn2El = document.body.children[1];
btn2El.onclick = function () {
alert("监听方式2");
}
// 监听方式三 addListenEvent
var btn3El = document.body.children[2];
btn3El.addEventListener("click", function () {
alert("监听方式3");
})
</script>
鼠标事件:
键盘事件:
表单(form)元素事件:
时。
。Document 事件:
CSS 事件:
事实上对于事件有一个概念叫做事件流,为什么会产生事件流呢?
对着一个元素点击时,你点击的不仅仅是这个元素本身
;父子元素叠加层级
的;<div class="box">
<span class="word">哈哈哈哈</span>
</div>
// 认识事件流
var boxEl = document.querySelector(".box");
var wordEl = document.querySelector(".word");
boxEl.addEventListener("click", function() {
console.log("boxboxbox");
})
wordEl.addEventListener("click", function () {
console.log("wordwordword");
})
我们会发现默认情况下事件是从最内层的span向外依次传递的顺序,这个顺序我们称之为事件冒泡
(Event Bubble);
事实上,还有另外一种监听事件流的方式就是从外层到内层(body -> span),这种称之为事件捕获
(Event Capture);
为什么会产生两种不同的处理流呢?
完全相反
的事件流来对事件进行了传递;那么我们如何去监听事件捕获的过程呢?
如果我们都监听,那么会按照如下顺序来执行:
捕获阶段
(Capturing phase):
目标阶段
(Target phase):
冒泡阶段
(Bubbling phase):
事实上,我们可以通过event对象来获取当前的阶段:
开发中通常会使用事件冒泡
,所以事件捕获了解即可。
// 默认情况下是事件冒泡
spanEl.addEventListener("click", function() {
console.log("span元素发生了点击~冒泡")
})
divEl.addEventListener("click", function() {
console.log("div元素发生了点击~冒泡")
})
bodyEl.addEventListener("click", function() {
console.log("body元素发生了点击~冒泡")
})
// 设置希望监听事件捕获的过程
spanEl.addEventListener("click", function() {
console.log("span元素发生了点击~捕获")
}, true)
divEl.addEventListener("click", function() {
console.log("div元素发生了点击~捕获")
}, true)
bodyEl.addEventListener("click", function() {
console.log("body元素发生了点击~捕获")
}, true)
当一个事件发生时,就会有和这个事件相关的很多信息:
类型
是什么,你点击的是哪一个元素
,点击的位置
是哪里等等相关的信息;Event对象
中,这个对象由浏览器创建
,称之为event对象
;如何获取这个event对象呢?
函数回调
时,被系统传入;这个对象中都有哪些常见的属性和操作呢?
常见的属性:
type
:事件的类型;target
:当前事件发生的元素;currentTarget
:当前处理事件的元素;eventPhase
:事件所处的阶段;offsetX
、offsetY
:事件发生在元素内的位置;clientX
、clientY
:事件发生在客户端内的位置;pageX
、pageY
:事件发生在客户端相对于document的位置;screenX
、screenY
:事件发生相对于屏幕的位置;常见的方法:
preventDefault
:取消事件的默认行为;stopPropagation
:阻止事件的进一步传递(冒泡或者捕获都可以阻止);// 认识事件流
var boxEl = document.querySelector(".box");
var wordEl = document.querySelector(".word");
// 事件冒泡
wordEl.addEventListener("click", function (event) {
console.log("word冒泡", event.target, event.currentTarget);
console.log(event.type);//click
console.log(event.eventPhase);//2
})
wordEl.addEventListener("click", function (event) {
console.log("word捕获", event.target, event.currentTarget);
console.log(event.type);//click
console.log(event.eventPhase);//2
}, true)
boxEl.addEventListener("click", function (event) {
console.log("box捕获", event.target, event.currentTarget);
console.log(event.type);//click
console.log(event.eventPhase);//1
}, true)
document.body.addEventListener("click", function (event) {
console.log("body捕获", event.target, event.currentTarget);
console.log(event.type);//click
console.log(event.eventPhase);//1
// 停止传递
// event.stopPropagation();
}, true)
var aEl = document.querySelector("a");
console.log(aEl);
console.log(aEl.href);
aEl.addEventListener("click", function (event) {
console.log("a标签冒泡");
// 阻止默认行为:比如a标签的跳转
event.preventDefault();
})
在函数中,我们也可以通过this来获取当前的发生元素:
divEl.onclick = function(event) {
console.log(this)
console.log(event.currentTarget)
console.log(divEl)
console.log(this === divEl)
}
这是因为在浏览器内部,调用event handler是绑定到当前的target上的
我们会发现,所有的节点、元素都继承自EventTarget
那么这个EventTarget是什么呢?
添加
、删除
、派发
Event事件;EventTarget常见的方法:
addEventListener
:注册某个事件类型以及事件处理函数;removeEventListener
:移除某个事件类型以及事件处理函数;dispatchEvent
:派发某个事件类型到EventTarget上;var btnEl = document.querySelector("button")
// 1.将监听函数移除的过程
// var foo = function() {
// console.log("监听到按钮的点击")
// }
// btnEl.addEventListener("click", foo)
// // 需求: 过5s钟后, 将这个事件监听移除掉
// setTimeout(function() {
// btnEl.removeEventListener("click", foo)
// }, 5000)
// 这种做法是无法移除的
btnEl.addEventListener("click", function() {
console.log("btn监听的处理函数~")
})
setTimeout(function() {
btnEl.removeEventListener("click", function() {})
}, 5000)
// 派发事件
setTimeout(() => {
// 3秒后触发点击事件
btnEl.dispatchEvent(new Event("click"));
}, 3000);
事件冒泡在某种情况下可以帮助我们实现强大的事件处理模式 – 事件委托模式
(也是一种设计模式)
那么这个模式是怎么样的呢?
子元素被点击
时,父元素可以通过冒泡可以监听到子元素的点击
;event.target
获取到当前监听的元素;案例:一个ul中存放多个li,点击某一个li会变成红色
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<style>
ul,li {
list-style: none;
margin: 0;
padding: 0;
}
.item {
display: inline-block;
padding: 20px;
}
.active {
background-color: yellow;
color: blue;
}
style>
head>
<body>
<ul>
<li class="item">吃饭睡觉打豆豆li>
<li class="item">吃饭睡觉打豆豆li>
<li class="item">吃饭睡觉打豆豆li>
<li class="item">吃饭睡觉打豆豆li>
<li class="item">吃饭睡觉打豆豆li>
ul>
<script>
var ulEl = document.querySelector("ul");
ulEl.addEventListener("click", function (event) {
// 委托模式
// 获取触发事件的元素
event.target.classList.toggle("active");
})
script>
body>
html>
某些事件委托可能需要对具体的子组件进行区分,这个时候我们可以使用data-*
对其进行标记:
比如多个按钮的点击,区分点击了哪一个按钮:
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
head>
<body>
<div class="box">
<button data-action="search">搜索~button>
<button data-action="new">新建~button>
<button data-action="remove">移除~button>
<button>1111button>
div>
<script>
var boxEl = document.querySelector(".box")
boxEl.onclick = function(event) {
var btnEl = event.target
var action = btnEl.dataset.action
switch (action) {
case "remove":
console.log("点击了移除按钮")
break
case "new":
console.log("点击了新建按钮")
break
case "search":
console.log("点击了搜索按钮")
break
default:
console.log("点击了其他")
}
}
script>
body>
html>
接下来我们来看一下常见的鼠标事件(不仅仅是鼠标设备,也包括模拟鼠标的设备,比如手机、平板电脑)
常见的鼠标事件:
mouseenter和mouseleave
mouseover和mouseout
支持冒泡
var boxEl = document.querySelector(".box");
var containerEl = document.querySelector(".container");
// mouseenter mouseleave
// containerEl.addEventListener("mouseenter", function (event) {
// console.log("鼠标进来拉")
// })
// containerEl.addEventListener("mouseleave", function (event) {
// console.log("鼠标离开拉")
// })
// mouseover mouseout
containerEl.addEventListener("mouseover", function (event) {
console.log("鼠标进来拉")
})
containerEl.addEventListener("mouseout", function (event) {
console.log("鼠标离开拉")
})
事件的执行顺序是 onkeydown、onkeypress、onkeyup
我们可以通过key和code来区分按下的键:
var inputEl = document.querySelector("input")
var btnEl = document.querySelector("button")
// inputEl.onkeydown = function() {
// console.log("onkeydown")
// }
// inputEl.onkeypress = function() {
// console.log("onkeypress")
// }
// inputEl.onkeyup = function(event) {
// console.log(event.key, event.code)
// }
// 1.搜索功能
btnEl.onclick = function() {
console.log("进行搜索功能", inputEl.value)
}
inputEl.onkeyup = function(event) {
if (event.code === "Enter") {
console.log("进行搜索功能", inputEl.value)
}
}
// 2.按下s的时候, 搜索自动获取焦点
document.onkeyup = function(event) {
if (event.code === "KeyS") {
inputEl.focus()
}
}
针对表单也有常见的事件:
var inputEl = document.querySelector("input")
// 1.获取焦点和失去焦点
// inputEl.onfocus = function() {
// console.log("input获取到了焦点")
// }
// inputEl.onblur = function() {
// console.log("input失去到了焦点")
// }
// 2.内容发生改变/输入内容
// 输入的过程: input
// 内容确定发生改变(离开): change
// inputEl.oninput = function() {
// console.log("input事件正在输入内容", inputEl.value)
// }
// inputEl.onchange = function() {
// console.log("change事件内容发生改变", inputEl.value)
// }
// 3.监听重置和提交
var formEl = document.querySelector("form")
formEl.onreset = function(event) {
console.log("发生了重置事件")
event.preventDefault()
}
formEl.onsubmit = function(event) {
console.log("发生了提交事件")
// axios库提交
event.preventDefault()
}
DOMContentLoaded
:浏览器已完全加载 HTML,并构建了 DOM 树,但像 和样式表之类的外部资源可能尚未加载 完成。
load
:浏览器不仅加载完成了 HTML,还加载完成了所有外部资源:图片,样式等。
// 注册事件监听
window.addEventListener("DOMContentLoaded", function() {
// 1.这里可以操作box, box已经加载完毕
// var boxEl = document.querySelector(".box")
// boxEl.style.backgroundColor = "orange"
// console.log("HTML内容加载完毕")
// 2.获取img对应的图片的宽度和高度
var imgEl = document.querySelector("img")
console.log("图片的宽度和高度:", imgEl.offsetWidth, imgEl.offsetHeight)
})
window.onload = function() {
console.log("文档中所有资源都加载完毕")
// var imgEl = document.querySelector("img")
// console.log("图片的宽度和高度:", imgEl.offsetWidth, imgEl.offsetHeight)
}
window.onresize = function() {
console.log("创建大小发生改变时")
}
事件类型:https://developer.mozilla.org/zh-CN/docs/Web/Events