我正在参加 码上掘金体验活动,详情:show出你的创意代码块
##前言 今天我们要实现一个镂空遮罩找线索的小交互。通过本案例可以学习了解到如下知识点:
- 镂空遮罩的实现
- 元素堆叠时指针事件的处理
创建镂空窗口
之前做h5编辑器时这种功能采用的是canvas去画出相应的镂空区域。这里想偷个懒!
思来想去可以直接用box-shadow设置一个超大的外部阴影。
不了解的jy戳链接:box-shadow
<div id="opening" class="opening"></div>
//css
.opening {
position: absolute;
width: 150px;
height: 150px;
top: 403px;
left: 420px;
background: rgba(255, 255, 255, 0);
box-shadow: rgba(0, 0, 0, .92) 0 0 0 3366px; //重点
backdrop-filter: blur(1px);
border-radius: 50%;
z-index: 3;
pointer-events: none;
}
创建线索点
<div id="target" class="target">线索一</div>
.target {
position: absolute;
width: 80px;
height: 80px;
text-align: center;
line-height: 80px;
top: 242px;
left: 748px;
z-index: 2;
border-radius: 50%;
border: 2px solid rgb(145, 5, 5);
color: rgb(145, 5, 5);
pointer-events: auto;
}
拖动窗口并找到线索
拖拽相信文章有很多就不废话了(这里有个vue的图片拖拽组件有兴趣可以下载),主要就是监听onmousedown事件和onmousemove监听鼠标移动距离。然后把距离差计算赋值给当前窗口。我们要考虑的是,不仅要拖拽并且需要点击到遮罩层下面的线索元素。
通过测试发现z-index层级小的元素被遮挡无法触发点击事件或者说不能同时触发多个非父子堆叠元素的事件。
解决思路:
拖拽事件绑定在父元素上,然后改变镂空窗口。
<div id="box" class="box">
<div id="opening" class="opening"></div>
<div id="target" class="target">线索一</div>
</div>
//js
let box = document.getElementById('box')
let opening = document.getElementById('opening')
box.onmousedown = function (ev) {
let e = ev || event;
let x = e.clientX - opening.offsetLeft;
let y = e.clientY - opening.offsetTop;
document.onmousemove = function (ev) {
let e = ev || event;
opening.style.left = ev.clientX - x + 'px';
opening.style.top = ev.clientY - y + 'px';
let bodyScreenX = ev.screenX
let bodyClientWidth = document.body.clientWidth
}
}
最后当点击线索元素时触发id=target的事件!
重点
因为镂空窗口层级比线索元素层级高,拖动找到时正好挡住了,所以我们要使用一个小帮手:
pointer-events: none; 元素不对指针事件做出反应。链接
<div class="alert" id="alert" style="display: none;">
成功!下一关
</div>
//点击
document.getElementById('target').onclick = function (e) {
alert('线索已找到!')
document.getElementById('alert').style.display = 'block'
}
ps:因为alert好像没用,加了个遮罩提示。
结尾
代码块使用起来感觉不错,不过希望以后支持react、vue等