前言概述
JavaScript 结合 CSS 打造的一款图片特效,当鼠标拖拽滑块时,让本该置灰的图片局部恢复本来的颜色。且该效果随着你的鼠标的按下时的移动而移动。
核心功能
- 图片置灰
- 拖拽功能
- 让滑块位置处的图片恢复本来的颜色
实现原理
这个的实现原理并不复杂,我们只需要一张背景图作为我们的素材,再单独定义一个滑块让并使用背景图裁剪的方式动态去显示图片的不同位置。
实现手电筒的框架
搭建框架
要实现这个功能,首先需要根据结构搭建一个样式结构出来
// css
/* 外层容器 */
.container {
position: relative;
width: 500px;
height: 300px;
}
/* 图片 */
.baImg {
display: block;
width: 100%;
height: 100%;
filter: grayscale(100%);
user-select: none;
/* 阻止图片被拖拽 */
-webkit-user-drag: none;
}
/* 手电筒 */
.move {
position: absolute;
width: 100px;
height: 100px;
top: 0;
left: 0;
border-radius: 50%;
background: url("./1.png") no-repeat;
background-size: 500px 300px;
background-position: 0 0;
/* 增加盒子阴影 */
box-shadow: 0 0 5px 5px #fff;
}
// html
<div class="container">
<!-- 背景图 -->
<img class="baImg" src="./1.png" alt="">
<!-- 手电筒 -->
<div class="move"></div>
</div>
!! -webkit-user-drag: none; 是 CSS 控制一个元素和它的内容是否可以被拖拽
取值
auto:使用默认的拖拽行为,这种情况只有图片和链接可以被拖拽。
element:整个元素(不仅仅只是它的内容)可拖拽。
none:元素不能被拖动。在通过选中后可拖拽。
filter: grayscale(100%); 是 CSS 用来定义元素(通常是图片)的视觉滤镜效果
grayscale: 将图片转换为灰阶,数值的大小表示转换的程度,区间在 0 - 100
更多参数可以参考 菜鸟教程- filter 的使用
根据上述的样式和结构搭建出来的结果,它就长下图这个样子
逻辑处理
首先我们需要给手电筒增加拖拽功能,在拖拽过程中动态获取鼠标的移动距离,然后更新手电筒本身的位置,并使用 background-clip 背景图裁剪的方式将原图的部分区域裁剪到手电筒的容器内显示原图,这样基本上就可以实现手电筒的效果了。
- 获取外层容器和手电筒的元素,并用容器的大小减去手电筒本身的大小
- 给手电筒增加拖拽效果,根据上述计算出来的大小限制拖拽范围
- 拖拽过程中得到拖拽的位置,更新手电筒本身的位置、背景图裁剪的位置
// 获取最外层的容器
let container = document.getElementsByClassName('container')[0];
// 获取手电筒
let move = document.getElementsByClassName('move')[0];
// 容器的大小减去移动目标的大小得到,X、Y 拖拽距离上的最大拖拽范围
let maxWidth = container.clientWidth - move.clientWidth;
let maxHeight = container.clientHeight - move.clientHeight;
move.onmousedown = function (moveStart) {
// 获取鼠标在元素身上点下的位置
let left = moveStart.offsetX;
let top = moveStart.offsetY;
document.onmousemove = function (ev) {
// 获取拖拽后鼠标距离可视区的位置
let { clientX, clientY } = ev;
let _cX = clientX - left;
let _cY = clientY - top;
// 限制手电筒的移动范围
if (_cX <= 0) {
_cX = 0;
} else if (_cX >= maxWidth) {
_cX = maxWidth;
}
if (_cY <= 0) {
_cY = 0;
} else if (_cY >= maxHeight) {
_cY = maxHeight;
}
move.style.left = (_cX) + 'px';
move.style.top = (_cY) + 'px';
// !!!! 这里的背景图裁剪一定要是负的,如果是正数就会出现问题
move.style.backgroundPosition = `-${_cX}px -${_cY}px`;
}
// 在拖拽结束后,将绑定在 document 身上的事件删除,避免重复绑定和触发
document.onmouseup = function () {
console.log('关闭');
document.onmousemove = null;
document.onmouseup = null;
}
}
实现效果
在手电筒上按下拖拽移动的时候,就可以看到在手电筒的区域显示了原图本来的色彩
总结
到这里看一下我们都一起实现文章开头说的这些功能
- 图片置灰
- 拖拽功能
- 让滑块位置处的图片恢复本来的颜色
完整代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>手电筒</title>
<style>
/* 外层容器 */
.container {
position: relative;
width: 500px;
height: 300px;
}
/* 图片 */
.baImg {
display: block;
width: 100%;
height: 100%;
filter: grayscale(100%);
user-select: none;
/* 阻止图片被拖拽 */
-webkit-user-drag: none;
}
/* 手电筒 */
.move {
position: absolute;
width: 100px;
height: 100px;
top: 0;
left: 0;
border-radius: 50%;
background: url("./1.png") no-repeat;
background-size: 500px 300px;
background-position: 0 0;
/* 增加盒子阴影 */
box-shadow: 0 0 5px 5px #fff;
}
</style>
</head>
<body>
<div class="container">
<!-- 背景图 -->
<img class="baImg" src="./1.png" alt="">
<!-- 手电筒 -->
<div class="move"></div>
</div>
<script>
// 获取最外层的容器
let container = document.getElementsByClassName('container')[0];
// 获取手电筒
let move = document.getElementsByClassName('move')[0];
// 容器的大小减去移动目标的大小得到,X、Y 拖拽距离上的最大拖拽范围
let maxWidth = container.clientWidth - move.clientWidth;
let maxHeight = container.clientHeight - move.clientHeight;
move.onmousedown = function (moveStart) {
// 获取鼠标在元素身上点下的位置
let left = moveStart.offsetX;
let top = moveStart.offsetY;
document.onmousemove = function (ev) {
// 获取拖拽后鼠标距离可视区的位置
let { clientX, clientY } = ev;
let _cX = clientX - left;
let _cY = clientY - top;
// 限制手电筒的移动范围
if (_cX <= 0) {
_cX = 0;
} else if (_cX >= maxWidth) {
_cX = maxWidth;
}
if (_cY <= 0) {
_cY = 0;
} else if (_cY >= maxHeight) {
_cY = maxHeight;
}
move.style.left = (_cX) + 'px';
move.style.top = (_cY) + 'px';
// !!!! 这里的背景图裁剪一定要是负的,如果是正数就会出现问题
move.style.backgroundPosition = `-${_cX}px -${_cY}px`;
}
// 在拖拽结束后,将绑定在 document 身上的事件删除,避免重复绑定和触发
document.onmouseup = function () {
console.log('关闭');
document.onmousemove = null;
document.onmouseup = null;
}
}
</script>
</body>
</html>
本篇实现手电筒效果就到此结束了,这个效果用到的场景比较少,如果读者有更好的思路或者实现效果的话,欢迎在评论区活跃讨论。文章中的案例可以正常使用哦 ~