猴赛雷的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; 即可完美的实现我们要实现的功能了

相关推荐
溪语流沙14 分钟前
【每天一个CSS | Day19】流光文字与一笔写成的手写签名
前端·javascript·css
逐光者93320 分钟前
STM32——SPI 屏 · Flash · 高速
java·前端·stm32
To_OC28 分钟前
同样是让 AI 写全栈,为什么别人一句话就够了
前端·前端框架·next.js
CDwenhuohuo41 分钟前
electron pc项目打包成桌面端
前端·javascript·electron
前端大斗师43 分钟前
「大于 1000」把 1000 元那单也算进去了:我在 Vue3 订单页对了 10 句话
前端·人工智能·typescript·大模型·原力计划
Jmyd01231 小时前
用 Web VR 引擎搭建 3D 虚拟展厅:从素材上云到多端实时渲染的完整数据链路
前端·3d·vr·三维数字化
刘天远2 小时前
Agent成本核算实现:事件表、状态分布与Python归集
前端·数据库·人工智能·python
欣欣之王来了2 小时前
开发环境准备:Node.js、npm、VS Code安装配置
前端·学习·架构·项目·vue3教程
xiaolinudao1232 小时前
将多个 Excel 表格中的数据合并到单个表中|6 种实现方案全解析
java·前端·excel
LRL_3 小时前
跨平台 Node 模块安装指南:如何利用 pnpm/npm 配置`supportedArchitectures` 锁定平台依赖
前端·npm·node.js