今天接到一个给页面增加水印的需求。最开始使用绝对定位 position: absolute
+ z-index
+ opacity
方式实现了第一版,可以添加水印,但是鼠标事件的目标总是在水印容器元素上,无法复制水印下面的内容,体验非常差。遂在 github 上找到了watermark-dom包,使用简单,顺利完成了需求。
如果只是这样使用轮子,能力永远等不到增长,于是阅读了它的源码,除开一些通用化的接口和功能,核心思路和我的相同,但为啥他就可以操作水印下元素内容呢?最后发现其使用了 css 属性 pointer-events
。
pointer-events
pointer-events
指定在什么情况下元素可以成为鼠标事件的target
。
总共有以下几种值,具体可以查看MDN,有详细的介绍。这里只介绍以下默认值 auto
和 none
。
/* Keyword values */
pointer-events: auto;
pointer-events: none;
pointer-events: visiblePainted; /* SVG only */
pointer-events: visibleFill; /* SVG only */
pointer-events: visibleStroke; /* SVG only */
pointer-events: visible; /* SVG only */
pointer-events: painted; /* SVG only */
pointer-events: fill; /* SVG only */
pointer-events: stroke; /* SVG only */
pointer-events: all; /* SVG only */
/* Global values */
pointer-events: inherit;
pointer-events: initial;
pointer-events: unset;
pointer-events: auto
pointer-events: auto
与 pointer-events 属性未指定时的表现效果相同,对于 SVG 内容,该值与visiblePainted
效果相同。
也就是我最开始遇到的情况,鼠标的目标总是在水印层上,就像下面这样:
pointer-events: none
元素永远不会成为鼠标事件的 target。但是,当其后代元素的 pointer-events 属性指定其他值时,鼠标事件可以指向后代元素,在这种情况下,鼠标事件将在捕获或冒泡阶段触发父元素的事件监听器。
加上这个 css 属性后,效果如下:
注意
使用 pointer-events 来阻止元素成为鼠标事件目标不一定意味着元素上的事件侦听器永远不会触发。如果元素后代明确指定了 pointer-events 属性并允许其成为鼠标事件的目标,那么指向该元素的任何事件在事件传播过程中都将通过父元素,并以适当的方式触发其上的事件侦听器。当然,位于父元素但不在后代元素上的鼠标活动都不会被父元素和后代元素捕获(鼠标活动将会穿过父元素而指向位于其下面的元素)。
比如下面的例子:
<head>
<style>
.container {
position: relative;
display: block !important;
pointer-events: none !important;
}
.item {
position: absolute;
height: 100vh;
width: 100vw;
left: 0;
top: 0;
z-index: "999";
opacity: 0.7;
pointer-events: none !important;
}
.item2 {
pointer-events: auto;
}
</style>
</head>
<body>
<div class="container" id="container">
adasdasdasddddddddddddddddddddddddddd
<div class="item">
水印水印水印
</div>
<div class="item2">
哈哈哈哈哈哈
</div>
</div>
</body>
<script type="text/javascript">
document.getElementById("container").addEventListener("click", e => {
console.log(e);
});
</script>
总结
这个属性吧,基本上不会用到,但是了解下还是可以的。