Skip to content

事件处理 ​

一、认识事件处理 ​

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('文档中所有的资源都加载完毕')
})