CSS+ JS 实现手电筒效果
前言概述
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>
本篇实现手电筒效果就到此结束了,这个效果用到的场景比较少,如果读者有更好的思路或者实现效果的话,欢迎在评论区活跃讨论。文章中的案例可以正常使用哦 ~
相关文章:
CSS+ JS 实现手电筒效果
前言概述 JavaScript 结合 CSS 打造的一款图片特效,当鼠标拖拽滑块时,让本该置灰的图片局部恢复本来的颜色。且该效果随着你的鼠标的按下时的移动而移动。 核心功能 图片置灰 拖拽功能 让滑块位置处的图片恢复本来的颜色 实现原理 这个的实现原理并不…...
2021地理设计组二等奖:基于InSAR和指数分析的地面沉降风
作品简介 一、作品背景 地面沉降是指地面高程的降低, 又称地面下沉或地沉, 是以缓慢、难以察觉的向下垂直运动为主, 是指在自然和人为因素作用下, 由于地壳表层土体压缩而导致区域性地面标高降低的一种环境现象。目前, 地面沉降己成为城市化进程中普遍存在的生态环境问题, 成为…...
计算机操作系统(第四版)第二章进程的描述与控制—课后习题答案
1.什么是前趋图?为什么要引入前趋图? 前趋图是一个有向无循环图,记为DAG,用于描述进程之间执行的先后关系。 2.试画出下面四条语句的前趋图: S1:axy; S2:bz1; S3:ca-b; S4:wc1; 3.为什么程序并发执行会产生间断性特征&…...
CAN通信----电路图
CAN通信----基本原理 一、CAN总线网络连接 1.闭环总线网络----ISO11898 闭环总线网络高速、短距离,它的总线最大长度为 40m,通信速度最高为 1Mbps,总线的两端各要求有一个120 欧的电阻。 2.开环总线网络----ISO11519 开环总线网络低速、…...
Windows系统安装ElasticSearch(一)
一 ES介绍Elasticsearch 是一个分布式可扩展的实时搜索和分析引擎,一个建立在全文搜索引擎 Apache Lucene(TM) 基础上的搜索引擎.当然 Elasticsearch 并不仅仅是 Lucene 那么简单,它不仅包括了全文搜索功能,还可以进行以下工作:分布式实时文件存储&#…...
linux 产生随机数 并遍历
1、产生随机数 varRANDOMvarRANDOM varRANDOMvar[ $var % 150 ] 2、产生不重复的随机数 $ entries($(shuf -i 0-149 -n 15)) $ echo “${entries[]}” 3、对随机数排序 $ entries($(shuf -i 0-149 -n 15 | sort -n)) $ echo “entries[]"12224549546678798393118119124140…...
【3.24】Mybatis常见面试题
Mybatis常见面试题 #{}和¥{}的区别是什么? 【#】:底层执行SQL使用PreparedStatement对象,预编译SQL,相对安全。入参使用占位符的方式。 【$】:底层执行SQL使用Statement对象,入参使用SQL拼接的…...
IDEA 热部署,修改代码不用重启项目
热部署指在修改项目代码的时候不重启服务器让修改生效。安装JRebel and XRebelFile->Settings,然后Plugins-> Marketplace,输入JRebel,安装如下插件——JRebel and XRebel ,重启idea激活JRebel and XRebel第一行输入网址&am…...
将 XLS 转换为 EXE:xlCompiler Crack
只需单击几下即可将Excel文件转换为应用程序 xl编译器无需编程即可将您的Excel电子表格转换为软件应用程序 将 XLS 转换为 EXE 将Excel文件转换为具有保护选项的应用程序。Excel 到 EXE 转换器为您提供了分发 Excel 模型的竞争优势和灵活性。将 Excel 的功能丰富的环境保存在应…...
【百面成神】spring基础12问,你能坚持到第几问
前 言 🍉 作者简介:半旧518,长跑型选手,立志坚持写10年博客,专注于java后端 ☕专栏简介:java面试宝典,特点:全、精、深、简,力求每个核心知识点1分钟回答好。 dz…...
javaSE类和对象(下)
目录君1.封装2.访问限定符3.包的定义及使用4.static成员变量5.static成员方法6.代码块及其分类实例代码块静态代码块静态代码块与实例代码块的执行顺序static成员变量(类变量)初始化1.封装 面向对象程序三大特性:封装、继承、多态。而类和对象阶段,主要…...
【数据结构】第四站:单链表力扣题(二)
目录 一、链表的回文结构 二、相交链表 三、环形链表 四、环形链表Ⅱ 五、复制带随机指针的链表 一、链表的回文结构 题目描述:链表的回文结构_牛客题霸_牛客网 对于这道题,如果没有前面的一些题的基础,是非常难做的,我们的思…...
KafKa知识汇总
前言 汇总相关知识 Kafka快速实战与基本原理详解...
【RV1126】调试GT911,1024x600 7寸 MIPI 电容触摸屏
文章目录一、驱动注册失败二、触摸屏可以触摸,但是x轴数据反了三、可以触摸了,但是Y轴数据跳变,几乎只有一半的屏幕是可以正常滑动的三、汇顶触摸屏配置文件解析四、使用新的配置文件4.1 新配置解决问题4.2 测试触摸的方法在kernel增加frame …...
C的强符号/弱符号
首先上代码和结果: 代码: #include <stdio.h> int k; int k; int main() {printf("addr of k %p\n", &k);printf("value of k %d\n", k);return 0; }结果: addr of k 00408074 value of k 0问题&…...
AD/DA转换(XPT2046)
AD/DA介绍AD(Analog to Digital):模拟-数字转换,将模拟信号转换为计算机可操作的数字信号DA(Digital to Analog):数字-模拟转换,将计算机输出的数字信号转换为模拟信号AD/DA转换打开…...
乐观锁和悲观锁 面试题
Mysql的乐观锁和悲观锁 实现方式加锁时机常见的调用方式优势不足适用场景乐观锁开发自定义更新数据的时候sql语句中进行version的判断高并发容易出现不一致的问题高并发读,少写悲观锁Mysql内置查询数据的开始select * for update保证一致性低并发互联网高并发场景极…...
【Autoware规控】mpc_follower模型预测控制节点
文章目录1. 技术原理2. 代码实现1. 技术原理 MPC,即Model Predictive Control(模型预测控制),是一种基于动态模型的控制算法。MPC算法通过建立系统的数学模型,根据当前状态和一定时间内的预测,优化未来的控…...
成果VR虚拟3D展厅让内容更丰富饱满
随着数字技术的不断发展和普及,数字化展厅成为了一种重要的展示形式。线上虚拟展厅作为数字化展示的一种新形式,采用虚拟现实技术,能够克服时空限制,打破传统展览业的展示模式,为用户提供更加丰富、立体、沉浸式的展览…...
【CE进阶】lua脚本使用
▒ 目录 ▒🛫 导读需求开发环境1️⃣ 脚本窗口Lua ScriptLua EngineAuto assemble2️⃣ 全局变量3️⃣ 进程当前打开的进程ID系统的进程列表系统的顶部窗口列表4️⃣ 线程5️⃣ 输入设备6️⃣ 屏幕7️⃣ 剪贴板🛬 文章小结📖 参考资料&#x…...
《Playwright:微软的自动化测试工具详解》
Playwright 简介:声明内容来自网络,将内容拼接整理出来的文档 Playwright 是微软开发的自动化测试工具,支持 Chrome、Firefox、Safari 等主流浏览器,提供多语言 API(Python、JavaScript、Java、.NET)。它的特点包括&a…...
【JavaWeb】Docker项目部署
引言 之前学习了Linux操作系统的常见命令,在Linux上安装软件,以及如何在Linux上部署一个单体项目,大多数同学都会有相同的感受,那就是麻烦。 核心体现在三点: 命令太多了,记不住 软件安装包名字复杂&…...
Mysql8 忘记密码重置,以及问题解决
1.使用免密登录 找到配置MySQL文件,我的文件路径是/etc/mysql/my.cnf,有的人的是/etc/mysql/mysql.cnf 在里最后加入 skip-grant-tables重启MySQL服务 service mysql restartShutting down MySQL… SUCCESS! Starting MySQL… SUCCESS! 重启成功 2.登…...
从面试角度回答Android中ContentProvider启动原理
Android中ContentProvider原理的面试角度解析,分为已启动和未启动两种场景: 一、ContentProvider已启动的情况 1. 核心流程 触发条件:当其他组件(如Activity、Service)通过ContentR…...
【Elasticsearch】Elasticsearch 在大数据生态圈的地位 实践经验
Elasticsearch 在大数据生态圈的地位 & 实践经验 1.Elasticsearch 的优势1.1 Elasticsearch 解决的核心问题1.1.1 传统方案的短板1.1.2 Elasticsearch 的解决方案 1.2 与大数据组件的对比优势1.3 关键优势技术支撑1.4 Elasticsearch 的竞品1.4.1 全文搜索领域1.4.2 日志分析…...
【实施指南】Android客户端HTTPS双向认证实施指南
🔐 一、所需准备材料 证书文件(6类核心文件) 类型 格式 作用 Android端要求 CA根证书 .crt/.pem 验证服务器/客户端证书合法性 需预置到Android信任库 服务器证书 .crt 服务器身份证明 客户端需持有以验证服务器 客户端证书 .crt 客户端身份…...
【Redis】Redis从入门到实战:全面指南
Redis从入门到实战:全面指南 一、Redis简介 Redis(Remote Dictionary Server)是一个开源的、基于内存的键值存储系统,它可以用作数据库、缓存和消息代理。由Salvatore Sanfilippo于2009年开发,因其高性能、丰富的数据结构和广泛的语言支持而广受欢迎。 Redis核心特点:…...
Python爬虫(四):PyQuery 框架
PyQuery 框架详解与对比 BeautifulSoup 第一部分:PyQuery 框架介绍 1. PyQuery 是什么? PyQuery 是一个 Python 的 HTML/XML 解析库,它采用了 jQuery 的语法风格,让开发者能够用类似前端 jQuery 的方式处理文档解析。它的核心特…...
今日行情明日机会——20250609
上证指数放量上涨,接近3400点,个股涨多跌少。 深证放量上涨,但有个小上影线,相对上证走势更弱。 2025年6月9日涨停股主要行业方向分析(基于最新图片数据) 1. 医药(11家涨停) 代表标…...
短视频时长预估算法调研
weighted LR o d d s T p 1 − p ( 1 − p ) o d d s T p ( T p o d d s ∗ p ) o d d s p o d d s T o d d s odds \frac{Tp}{1-p} \newline (1-p)odds Tp \newline (Tp odds * p) odds \newline p \frac{odds}{T odds} \newline odds1−pTp(1−p)oddsTp(Tpodds…...
