事件处理
一、认识事件处理
web 页面需要和用户之间进行交互,而交互的过程中需要捕捉交互的过程;
比如用户点击了某个按钮、用户在输入框里面输入了某个文本、用户鼠标经过了某个位置;
浏览器需要搭建一条 JavaScript 代码和事件之间的桥梁;
当某个事件发生时,让 JavaScript 可以响应(执行某个函数),所以需要针对事件编写处理程序。
监听方式
- 在 JavaScript 中直接监听
javascript
<button onclick="console.log('按钮发生了点击')">按钮</button>- dom 属性,通过元素的
on来监听
html
<button class="btn">按钮</button>
<script>
var btnEl = document.querySelector('.btn')
btnEl.onclick = function () {
console.log('按钮发生了点击')
}
</script>- 通过 EventTarget 的
addEventListener来监听
html
<button class="btn">按钮</button>
<script>
var btnEl = document.querySelector('.btn')
btnEl.addEventListener('click', function () {
console.log('按钮发生了点击1')
})
btnEl.addEventListener('click', function () {
console.log('按钮发生了点击2')
})
</script>二、事件冒泡和事件捕获
事件流
在浏览器上对一个元素点击时,点击的不仅仅是这个元素本身.
因为 html 元素是存在父子元素叠加层级的,
比如 span 元素是放在 div 元素上的,
div 元素是放在 body 元素上的,
body 元素是放在 html 元素上的。
冒泡
最内层往最外层传递
捕获
最外层往最内层传递
html
<style>
.box {
display: flex;
justify-content: center;
align-items: center;
width: 200px;
height: 200px;
background-color: teal;
}
.box span {
width: 100px;
height: 100px;
background: tomato;
}
</style>
<div class="box">
<span></span>
</div>
<script>
var bodyEl = document.body
var divEl = document.querySelector('div')
var spanEl = document.querySelector('span')
// 事件冒泡
bodyEl.onclick = function () {
console.log('body元素发生了点击')
}
divEl.onclick = function () {
console.log('div元素发生了点击')
}
spanEl.onclick = function () {
console.log('span元素发生了点击')
}
// 事件捕获
bodyEl.addEventListener(
'click',
function () {
console.log('body元素发生了点击')
},
true
)
divEl.addEventListener(
'click',
function () {
console.log('div元素发生了点击')
},
true
)
spanEl.addEventListener(
'click',
function () {
console.log('span元素发生了点击')
},
true
)
</script>三、事件对象 event
常见属性
- type: 事件类型
- target: 当前事件发生的元素
- currentTarget: 当前处理事件的元素
- eventPhase: 事件所处的阶段
- offsetX, offsetY: 事件发生在元素内的位置
- clientX, clientY: 事件发生在客户端内的位置
- pageX, pageY: 事件发生在客户端相对于 document 的位置
- screenX, screenY: 事件发生相对于屏幕的位置
html
<style>
.box {
width: 200px;
height: 200px;
background-color: teal;
}
</style>
<div class="box"></div>
<script>
var boxEl = document.querySelector('.box')
boxEl.onclick = function (event) {
console.log('事件类型', event.type)
console.log('事件阶段', event.eventPhase)
console.log('事件元素中的位置', event.offsetX, event.offsetY)
console.log('事件客户端中的位置', event.clientX, event.clientY)
console.log('事件页面的位置', event.pageX, event.pageY)
console.log('事件屏幕的位置', event.screenX, event.screenY)
console.log(
event.target,
event.currentTarget,
event.target === event.currentTarget
)
}
</script>常见方法
preventDefault: 阻止默认行为
html
<a href="https://www.baidu.com"></a>
<script>
/* 阻止默认行为 */
aEl.onclick = function (event) {
console.log('a元素发生了点击')
event.preventDefault()
}
</script>stopPropagation: 阻止事件进一步传递冒泡和捕获都可以阻止
html
<div class="box">
<span>
<button>按钮</button>
</span>
</div>
<script>
var btnEl = document.querySelector('button')
var spanEl = document.querySelector('span')
var divEl = document.querySelector('div')
btnEl.addEventListener(
'click',
function (event) {
console.log('btn事件捕获')
},
true
)
spanEl.addEventListener(
'click',
function () {
console.log('span事件捕获')
},
true
)
divEl.addEventListener(
'click',
function () {
console.log('div事件捕获')
event.stopPropagation()
},
true
)
btnEl.addEventListener('click', function () {
console.log('btn事件冒泡')
})
spanEl.addEventListener('click', function () {
console.log('span事件冒泡')
})
divEl.addEventListener('click', function () {
console.log('div事件冒泡')
})
</script>- 事件处理函数中的 this 就是处理的元素
html
<button>按钮</button>
<script>
var btnEl = document.querySelector('button')
btnEl.onclick = function (event) {
console.log(this)
console.log(event.target)
console.log(event.currentTarget)
}
</script>四、EventTarget 使用
所有的节点、元素、window 都继承自EventTarget。
EventTarget 是 DOM 接口,用于添加、删除、派发 Event。
常见方法
addEventListener: 注册某个事件类型以及事件处理函数removeEventListener: 移除某个事件类型以及事件处理函数dispatchEvent: 派发某个事件类型到 EventTarget 上
html
<button>按钮</button>
<script>
var btnEl = document.querySelector('button')
var foo = function () {
console.log('监听到按钮点击')
}
// 注册
btnEl.addEventListener('click', foo)
// 移除
setTimeout(function (param) {
btnEl.removeEventListener('click', foo)
}, 5000)
// 派发
window.addEventListener('mocha', function () {
console.log('监听到mocha的呼唤~')
})
setTimeout(function () {
window.dispatchEvent(new Event('mocha'))
}, 5000)
</script>五、事件委托模式
子元素被点击时,父元素可以通过冒泡监听到子元素的点击,并且可以通过 event.target 获取到当前监听的元素。
html
<style>
.active {
color: red;
font-size: 20px;
background: orange;
}
</style>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
<li>7</li>
<li>8</li>
<li>9</li>
<li>10</li>
</ul>
<script>
var ulEl = document.querySelector("ul") // 记录当前被点击的元素 var activeLiEl
= null ulEl.onclick = function (event) { if (event.target !== ulEl) {
activeLiEl && activeLiEl.classList.remove("active")
event.target.classList.add("active") activeLiEl = event.target } }
</script>案例练习
html
<div class="box">
<button data-action="remove">移除</button>
<button data-action="new">新建</button>
<button data-action="search">搜索</button>
<button data-action="add">增加</button>
</div>
<script>
var boxEls = document.querySelector('.box')
boxEls.onclick = function (event) {
if (event.target !== boxEls) {
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>六、常见的事件
鼠标事件
- click: 点击某个对象时调用的事件句柄
- contextMenu: 点击鼠标右键打开上下文菜单时触发
- dblclick: 双击某个对象时调用的事件句柄
- mousedown: 鼠标按钮被按下
- mouseup: 鼠标按钮被松开
- mouseover: 鼠标移到某个元素上,支持冒泡
- mouseout: 鼠标从某个元素移开,支持冒泡
- mouseenter: 当鼠标指针移动到元素上时触发,不支持冒泡
- mouseleave: 当鼠标指针移出元素时触发,不支持冒泡
- mousemove: 鼠标被移动
html
<style>
.box {
width: 200px;
height: 200px;
background-color: orange;
}
</style>
<div class="box"></div>
<script>
var boxEl = document.querySelector('.box')
boxEl.onclick = function () {
console.log('点击')
}
boxEl.oncontextmenu = function (event) {
console.log('点击了右键')
// 阻止默认行为:右键打开菜单
event.preventDefault()
}
/* 记录鼠标是否按下 */
var isDown = false
boxEl.onmousedown = function () {
console.log('按下')
isDown = true
}
boxEl.onmouseup = function () {
console.log('抬起')
isDown = false
}
boxEl.onmousemove = function () {
if (isDown) {
console.log('移动')
}
}
</script>mouseover、mouseout和mouseenter、mouseleave的用法
html
<style>
.box {
display: flex;
justify-content: center;
align-items: center;
width: 200px;
height: 200px;
background-color: orange;
}
.box span {
width: 100px;
height: 100px;
background-color: red;
}
</style>
<div class="box">
<span></span>
</div>
<script>
var boxEl = document.querySelector('.box')
var spanEl = document.querySelector('span')
// 支持冒泡
boxEl.onmouseover = function () {
console.log('boxEl onmouseover')
}
boxEl.onmouseout = function () {
console.log('boxEl onmouseout')
}
// 不支持冒泡
spanEl.onmouseover = function () {
console.log('spanEl onmouseover')
}
spanEl.onmouseout = function () {
console.log('spanEl onmouseout')
}
</script>键盘事件
- onkeydown: 某个键盘按键被按下先发生
- onkeypress: 某个键盘按键被按下发生在文本被输入
- onkeyup: 某个键盘按键被松开发生在文本输入完成(抬起、松开)
html
<input type="text" />
<script>
var inputEl = document.querySelector('input')
inputEl.onkeydown = function () {
console.log('onkeydown')
}
inputEl.onkeypress = function () {
console.log('onkeypress')
}
inputEl.onkeyup = function (event) {
if (event.key === 'Enter') {
console.log(inputEl.value)
}
}
document.onkeyup = function (event) {
if (event.code === 'KeyS') {
inputEl.focus()
}
}
</script>表单事件
- onchange: 表单元素的内容改变时触发
- oninput: 元素获取用户输入时触发
- onfoucs: 元素获取焦点时触发
- onblur: 元素失去焦点时触发
- onreset: 表单重置时触发
- onsubmit: 表单提交时触发
html
<form action="">
<input type="text" />
<textarea
name=""
id=""
cols="30"
rows="10"
></textarea>
<button type="reset">重置</button>
<button type="submit">提交</button>
</form>
<script>
var formEl = document.querySelector('form')
var inputEl = document.querySelector('input')
inputEl.onfocus = function () {
console.log('获取焦点')
}
inputEl.onblur = function () {
console.log('失去焦点')
}
inputEl.oninput = function () {
console.log('正在输入内容:', inputEl.value)
}
inputEl.onchange = function () {
console.log('内容发生了改变 :', inputEl.value)
}
formEl.onreset = function () {
console.log('重置')
}
formEl.onsubmit = function (event) {
console.log('提交')
event.preventDefault()
// axios ->
}
</script>文档加载事件
- DOMContentLoaded: 浏览器已完全加载 HTML,并构建了 DOM 树,但想 img 和样式表之类的外部支援可能尚未加载完成
javascript
window.addEventListener('DOMContentLoaded', function () {
console.log('html内容加载完毕')
})ss
- load: 浏览器不仅加载完成了 HTML,还加载完了所有外部资源,图片,样式等
javascript
window.addEventListener('loaad', function () {
console.log('文档中所有的资源都加载完毕')
})