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…...
Spark 之 入门讲解详细版(1)
1、简介 1.1 Spark简介 Spark是加州大学伯克利分校AMP实验室(Algorithms, Machines, and People Lab)开发通用内存并行计算框架。Spark在2013年6月进入Apache成为孵化项目,8个月后成为Apache顶级项目,速度之快足见过人之处&…...
VB.net复制Ntag213卡写入UID
本示例使用的发卡器:https://item.taobao.com/item.htm?ftt&id615391857885 一、读取旧Ntag卡的UID和数据 Private Sub Button15_Click(sender As Object, e As EventArgs) Handles Button15.Click轻松读卡技术支持:网站:Dim i, j As IntegerDim cardidhex, …...
苍穹外卖--缓存菜品
1.问题说明 用户端小程序展示的菜品数据都是通过查询数据库获得,如果用户端访问量比较大,数据库访问压力随之增大 2.实现思路 通过Redis来缓存菜品数据,减少数据库查询操作。 缓存逻辑分析: ①每个分类下的菜品保持一份缓存数据…...
【android bluetooth 框架分析 04】【bt-framework 层详解 1】【BluetoothProperties介绍】
1. BluetoothProperties介绍 libsysprop/srcs/android/sysprop/BluetoothProperties.sysprop BluetoothProperties.sysprop 是 Android AOSP 中的一种 系统属性定义文件(System Property Definition File),用于声明和管理 Bluetooth 模块相…...
ABAP设计模式之---“简单设计原则(Simple Design)”
“Simple Design”(简单设计)是软件开发中的一个重要理念,倡导以最简单的方式实现软件功能,以确保代码清晰易懂、易维护,并在项目需求变化时能够快速适应。 其核心目标是避免复杂和过度设计,遵循“让事情保…...
Angular微前端架构:Module Federation + ngx-build-plus (Webpack)
以下是一个完整的 Angular 微前端示例,其中使用的是 Module Federation 和 npx-build-plus 实现了主应用(Shell)与子应用(Remote)的集成。 🛠️ 项目结构 angular-mf/ ├── shell-app/ # 主应用&…...
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.登…...
人工智能--安全大模型训练计划:基于Fine-tuning + LLM Agent
安全大模型训练计划:基于Fine-tuning LLM Agent 1. 构建高质量安全数据集 目标:为安全大模型创建高质量、去偏、符合伦理的训练数据集,涵盖安全相关任务(如有害内容检测、隐私保护、道德推理等)。 1.1 数据收集 描…...
在RK3588上搭建ROS1环境:创建节点与数据可视化实战指南
在RK3588上搭建ROS1环境:创建节点与数据可视化实战指南 背景介绍完整操作步骤1. 创建Docker容器环境2. 验证GUI显示功能3. 安装ROS Noetic4. 配置环境变量5. 创建ROS节点(小球运动模拟)6. 配置RVIZ默认视图7. 创建启动脚本8. 运行可视化系统效果展示与交互技术解析ROS节点通…...
webpack面试题
面试题:webpack介绍和简单使用 一、webpack(模块化打包工具)1. webpack是把项目当作一个整体,通过给定的一个主文件,webpack将从这个主文件开始找到你项目当中的所有依赖文件,使用loaders来处理它们&#x…...
