猴赛雷的pointer-events,一个你可以用不到但是不能不知道的 CSS属性

之前有一次美团的面试,面试官问我:如果有两个元素,一个元素覆盖到另一个元素上,如何做到点击上面的元素触发下面的元素? 当时的我在工作生涯中其实并没遇到过这种问题,也没有想到为什么会有这种情况的出现,也只是凭着自己的工作经验想出一个可以通过父子元素冒泡的做法实现这个做法,面试官虽说这个方法确实可以实现这个需求,我向他询问应该如何实现这个功能的时候,才首次认识了我们在这篇文章中要了解的pointer-events属性。

pointer-event是什么?有什么作用?

pointer-events 属性用于设置元素是否对鼠标事件做出反应。 默认值为auto,就是元素对鼠标事件做出反应,可设置为pointer-events: none; 表示元素忽略鼠标事件。

用最简单的话来说,只要设置了pointer-events: none; 任何鼠标事件都将被无效化(例如:点击事件、鼠标移入移除、css的hover等)。

让我们上代码来看下没有设置pointer-events: none; 的效果是什么

html 复制代码
<!DOCTYPE html>
<html lang="zh">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>Document</title>
</head>
<style>
	#demo {
		width: 200px;
		height: 200px;
		background-color: aqua;
		text-align: center;
		line-height: 200px;
	}
	#demo:hover {
		background-color: bisque;
	}
</style>
<body>
	<div id="demo">我是测试的div</div>
	<script>
		const demo = document.getElementById('demo');
		demo.onclick = e => {
			console.log('点击了');
		};
		demo.onmouseenter = e => {
			console.log('移入了');
		};
		demo.onmouseleave = e => {
			console.log('移出了');
		}
	</script>
</body>
</html>

上面的代码写了一个div元素,我们在这个元素上绑定了点击、鼠标移入、鼠标移出这三个js鼠标事件,并在css上绑定了hover样式,鼠标进入会改变元素的背景色,现在这个demo是这个样子的

这个就是正常我们元素对鼠标事件响应的样子,接下来我们在demo元素上加上pointer-events: none; 属性 看一下是什么样子

html 复制代码
<!DOCTYPE html>
<html lang="zh">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>Document</title>
</head>
<style>
	#demo {
		width: 200px;
		height: 200px;
		background-color: aqua;
		text-align: center;
		line-height: 200px;
		pointer-events: none;
	}
	#demo:hover {
		background-color: bisque;
	}
</style>
<body>
	<div id="demo">我是测试的div</div>
	<script>
		const demo = document.getElementById('demo');
		demo.onclick = e => {
			console.log('点击了');
		};
		demo.onmouseenter = e => {
			console.log('移入了');
		};
		demo.onmouseleave = e => {
			console.log('移出了');
		}
	</script>
</body>
</html>

上面代码仅增加了一行pointer-events: none; 接下来我们看看元素对于鼠标事件是什么反应

我们可以看到代码中的js鼠标事以及hover全部都无效化了,元素没有对以上操作做出反应(鼠标点击选中文字是可以的)

现在我们知道了pointer-events的作用了,那我们来做一下文章开头说的面试题吧 一个元素覆盖在另一个元素,点击上面的元素触发下面元素的点击事件。

html 复制代码
<!DOCTYPE html>
<html lang="zh">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>Document</title>
</head>
<style>
	#demo {
		width: 350px;
		height: 400px;
		background-color: #f3f3f3;
		position: fixed;
		left: 50%;
		transform: translateX(-50%);
		color: red;
	}
	#bottom {
		width: 200px;
		height: 200px;
		background-color: red;
		position: absolute;
		top: 50%;
		left: 50%;
		transform: translate(-50%, -50%);
		z-index: 1;
		color: azure;
	}
	#top {
		width: 300px;
		height: 300px;
		background-color: yellow;
		position: absolute;
		top: 50%;
		left: 50%;
		transform: translate(-50%, -50%);
		opacity: 0.4;
		z-index: 2;
		color: black;
	}
</style>
<body>
	<div id="demo">
		我是父元素盒子
		<div id="bottom">我是下面的元素</div>
		<div id="top">我是上面的元素</div>
	</div>
	<script>
		const bottom = document.getElementById('bottom');
		bottom.onclick = e => {
			console.log('点击了');
		};
		bottom.onmouseenter = e => {
			console.log('移入了');
		};
		bottom.onmouseleave = e => {
			console.log('移出了');
		}
	</script>
</body>
</html>

在最上层盒子上加上 pointer-events: none; 之后

html 复制代码
<!DOCTYPE html>
<html lang="zh">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>Document</title>
</head>
<style>
	#demo {
		width: 350px;
		height: 400px;
		background-color: #f3f3f3;
		position: fixed;
		left: 50%;
		transform: translateX(-50%);
		color: red;
	}
	#bottom {
		width: 200px;
		height: 200px;
		background-color: red;
		position: absolute;
		top: 50%;
		left: 50%;
		transform: translate(-50%, -50%);
		z-index: 1;
		color: azure;
	}
	#top {
		width: 300px;
		height: 300px;
		background-color: yellow;
		position: absolute;
		top: 50%;
		left: 50%;
		transform: translate(-50%, -50%);
		opacity: 0.4;
		z-index: 2;
		color: black;
		pointer-events: none;
	}
</style>
<body>
	<div id="demo">
		我是父元素盒子
		<div id="bottom">我是下面的元素</div>
		<div id="top">我是上面的元素</div>
	</div>
	<script>
		const bottom = document.getElementById('bottom');
		bottom.onclick = e => {
			console.log('点击了');
		};
		bottom.onmouseenter = e => {
			console.log('移入了');
		};
		bottom.onmouseleave = e => {
			console.log('移出了');
		}
	</script>
</body>
</html>

pointer-events 的基础知识我们就说完了,附上一个最近在实际工作中使用pointer-events完成的一个功能模块的图片吧(工作代码就不展示了,就当做是一个使用场景,以后有这种需求的话可以用pointer-events进行实现)。

需求:有一个球场的图片,里面分割了很多模块,点击某一模块展示一个模块被选中的样式。

当时的第一想法就是背景图上覆盖元素,图片上有24个模块,只需要循环24个元素覆盖到上面,点击的时候某个模块展示被选中的样式就好,做出来的效果就是这样的

这么做的问题就是,整个背景图都会被覆盖掉,球场线根本就看不到,尤其是我全都选中之后,根本就看不出这是个球场了,所以就稍加改动,让背景图覆盖我要展示选中的元素上面,通过给背景图所在元素上添加pointer-events: none; 即可完美的实现我们要实现的功能了

相关推荐
优雅永不过时·20 分钟前
Three.js 原生 实现 react-three-fiber drei 的 磨砂反射的效果
前端·javascript·react.js·webgl·threejs·three
神夜大侠3 小时前
VUE 实现公告无缝循环滚动
前端·javascript·vue.js
明辉光焱3 小时前
【Electron】Electron Forge如何支持Element plus?
前端·javascript·vue.js·electron·node.js
柯南二号3 小时前
HarmonyOS ArkTS 下拉列表组件
前端·javascript·数据库·harmonyos·arkts
wyy72933 小时前
v-html 富文本中图片使用element-ui image-viewer组件实现预览,并且阻止滚动条
前端·ui·html
前端郭德纲4 小时前
ES6的Iterator 和 for...of 循环
前端·ecmascript·es6
王解4 小时前
【模块化大作战】Webpack如何搞定CommonJS与ES6混战(3)
前端·webpack·es6
欲游山河十万里4 小时前
(02)ES6教程——Map、Set、Reflect、Proxy、字符串、数值、对象、数组、函数
前端·ecmascript·es6
明辉光焱4 小时前
【ES6】ES6中,如何实现桥接模式?
前端·javascript·es6·桥接模式
PyAIGCMaster4 小时前
python环境中,敏感数据的存储与读取问题解决方案
服务器·前端·python