我正在参加 码上掘金体验活动,详情:show出你的创意代码块
💥特效与知识共存 之 🖱️鼠标操作
介绍
先看下gif图效果
如上图所示,能够看到我们通过操作鼠标,移动推拉线,展示左右对比图。
突然想做这个效果,是因为看到许多的AI型公司的页面,一般都会存在有这种功能。而且本能反应会想到通过鼠标操作,却如何实现效果呢?
分析
虽然说看着简单,但是涉及到的知识点确实 杂且多,这里我会细节讲述,所用到的技术及相关知识点。我们下面进行拆解和分析
1.页面搭建
首先是两张大的 优化前 Img1 和 优化后 的 Img2 图片,将其居中且重合放置,这一块通过 flex 布局 及 position 定位可以轻松解决。
接下来是我们的 推拉线,这个可以通过 position 定位也可以轻松的处理。
此时我们布局完后,页面效果应该下图这样
2.效果实现
可以看到 优化前的 Img1 图 会将 优化后的 Img2 图进行覆盖。
那么如何让被覆盖的 Img2 图进行部分展示,且保证 Img1 在位置不变的情况下,不将其覆盖。
clip
这个时候需要用到一个 css 属性,叫 clip,即 裁剪,此时我们给 优化前的 Img1图进行设置 clip 属性。
clip: rect(auto, auto, auto, 420px)
,分别对应的是 rect(<top>, <right>, <bottom>, <left>)
-
而我们只用到了 left,即相对于盒子的左边框边界的偏移。
-
auto 则代表元素不裁剪
<div id="old" style="clip: rect(auto, auto, auto, 420px);">
<img width="840" height="524" src='https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/cf0407e5da0d472aa253ee1aa36311b5~tplv-k3u1fbpfcp-watermark.image?' />
</div>
此时可以实现我们想要的效果了🎉,如下图。
但是在我看完 MDN 对它的讲解后,发现该特性已经从 Web 标准中删除。并提示尽量不要使用该特性。哭了😭😭😭
clip-path
幸好,MDN 提示了,可以使用新的属性 clip-path 来替换这个 Clip,我们辛苦在 MDN 上再学习下这个新属性,再实现上面的结果。
clip-path: polygon(420px 0%,100% 0%,100% 100%,420px 100%);
可以看到这是四个部分,即为四边形,分别代表着左上,右上,右下,左下,每个有两个参数,即坐标系的 x 的长度 和 y 的高度。
注意点:如果有六个部分,则是就是六边形。
好了,此时我们的效果也重新出现了🎉🎉🎉
<div id="new">
<img width="840" height="524"
src="https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/1c7ba67cdd174a9daf0ede7731d7c4d2~tplv-k3u1fbpfcp-watermark.image?"
alt="">
</div>
<div id="old" style="clip-path: polygon(420px 0%,100% 0%,100% 100%,420px 100%);">
<img width="840" height="524"
src='https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/cf0407e5da0d472aa253ee1aa36311b5~tplv-k3u1fbpfcp-watermark.image?' />
</div>
推拉线
可以看到我们的 推拉线 还未设置。这里有个知识点,既然要操作 推拉线,那么是选择 position 呢,还是 transform。
由于 position 会改变我们的盒模型,会引起进行重排(回流)操作。而重排所需的成本会比重绘高很多,所以我们这里用到的是 transform 属性✨✨✨
<div class="tech-drag" style="transform: translate(400px, 0);">
<div class="tech-drag-line"></div>
<img width="32" height="32"
src='https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/ed41b9b0aaae461d960c922090fbb23c~tplv-k3u1fbpfcp-watermark.image?' />
</div>
元素与浏览器的距离
因为后续要进行鼠标操作,所以这里先放上 盒子元素与浏览器的相关距离
这张图是借鉴菜鸟教程的
这里还有一个重要的 API,就是在我们去算当前元素到浏览器距离时,可以通过 getBoundingClientRect,这是它的 MDN介绍
在这个项目中,用到了当前元素的宽度 offsetWidth,以及当前元素距离浏览器左侧的值 getBoundingClientRect().left
鼠标操作
这里把项目中用到的鼠标操作的四种 API 说一下
- mousedown:鼠标落下事件
- mouseup:鼠标松开事件
- mouseleave:鼠标离开 所监听的元素 的事件
- mousemove:鼠标移动事件
推拉线
这里我们通过获取这个 推拉线 元素,针对 推拉线 做 mousedown 即鼠标 落下 的监听操作。
const techDrag = document.querySelector('.tech-drag')
techDrag.addEventListener('mousedown', (e) => {
active = true
techDrag.classList.add('dis-mouse')
})
可以看到这里有个 active 值,这个值的主要作用在后续我们移动鼠标时,判断是否是鼠标一直按着的状态。
而添加的类名,即为
.dis-mouse {
pointer-events: none;
}
代表,pointer-events: none;
,它的作用就是让这个元素无法进行鼠标操作。为什么要使用这个属性呢?
因为如果不加上这个属性,我们在拖动 推拉线 元素 时,如果是图片,就出现图片的虚影,如下图所示,相信大家都有见过。为了防止这种情况,我们将该元素进行所谓的隐藏,即让改元素暂时不接受鼠标事件。等鼠标 离开 或者 松开 时再解除这个属性即可。
外层 wrap
我们对外层包裹的 wrap 元素,进行鼠标 mouseup, mouseleave 即 松开 和 离开 的监听操作。
// 鼠标松开
wrap.addEventListener('mouseup', (e) => {
active = false
techDrag.classList.remove('dis-mouse')
})
// 鼠标离开
wrap.addEventListener('mouseleave', (e) => {
active = false
techDrag.classList.remove('dis-mouse')
})
移动操作
最后就是关键的移动操作逻辑,给我们的 body 元素监听 mousemove 鼠标移动事件。
// 鼠标移动事件
document.body.addEventListener('mousemove', (e) => {
if (active) {
useMouse(e)
}
})
接受当前参数值e,来获取当前鼠标位置距离浏览器左侧距离 e.pageX,与我们的 推拉线 距离鼠标左侧距离进行计算。
// 计算鼠标距离浏览器左侧的距离
let mousePageX = e.pageX;
// techDrag 距离浏览器左侧的距离
const techDragLeft = techDrag.getBoundingClientRect().left;
实时更新 推拉线 及 图片的切割,transform 和 clip-path 的值。
const getTechDragTransformX = () => {
return parseInt(techDrag.style.transform.split('(')[1].split('px')[0])
}
const setTechDragTransform = (val) => {
techDrag.style.transform = `translate(${val}px, 0px)`
}
const setOldImgClip = (val) => {
oldImg.style.clipPath = ` polygon(${val}px 0%,100% 0%,100% 100%,${val}px 100%)`
}
setTechDragTransform(newValue)
setOldImgClip(newValue + 20)
最终进行临界值判断,只有在临界值内,才进行移动,否则将其设置为临界值。
// 临界值判断
if (newValue < 0) return setTechDragTransform(0)
if (newValue > wrapWidth - techDragWidth) return setTechDragTransform(wrapWidth - techDragWidth)
总结
通过上面的一系列流程,我们的联动效果即可完成。这里把源码放到 码上掘金,小伙伴们可以去试试玩玩看😄,可能不是那么完美,还需改进。
这里用到的知识点,还是很杂的,得多总结,后续可能不止一次会用到💖
小知识点
为了在 码上掘金,图片加载速度快,这里将相关素材图片放置如下。小伙伴们记得点击玩玩,查看效果哦!