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…...
UE5 学习系列(二)用户操作界面及介绍
这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…...
XCTF-web-easyupload
试了试php,php7,pht,phtml等,都没有用 尝试.user.ini 抓包修改将.user.ini修改为jpg图片 在上传一个123.jpg 用蚁剑连接,得到flag...
MongoDB学习和应用(高效的非关系型数据库)
一丶 MongoDB简介 对于社交类软件的功能,我们需要对它的功能特点进行分析: 数据量会随着用户数增大而增大读多写少价值较低非好友看不到其动态信息地理位置的查询… 针对以上特点进行分析各大存储工具: mysql:关系型数据库&am…...
线程与协程
1. 线程与协程 1.1. “函数调用级别”的切换、上下文切换 1. 函数调用级别的切换 “函数调用级别的切换”是指:像函数调用/返回一样轻量地完成任务切换。 举例说明: 当你在程序中写一个函数调用: funcA() 然后 funcA 执行完后返回&…...
【JVM】- 内存结构
引言 JVM:Java Virtual Machine 定义:Java虚拟机,Java二进制字节码的运行环境好处: 一次编写,到处运行自动内存管理,垃圾回收的功能数组下标越界检查(会抛异常,不会覆盖到其他代码…...
将对透视变换后的图像使用Otsu进行阈值化,来分离黑色和白色像素。这句话中的Otsu是什么意思?
Otsu 是一种自动阈值化方法,用于将图像分割为前景和背景。它通过最小化图像的类内方差或等价地最大化类间方差来选择最佳阈值。这种方法特别适用于图像的二值化处理,能够自动确定一个阈值,将图像中的像素分为黑色和白色两类。 Otsu 方法的原…...
【Go】3、Go语言进阶与依赖管理
前言 本系列文章参考自稀土掘金上的 【字节内部课】公开课,做自我学习总结整理。 Go语言并发编程 Go语言原生支持并发编程,它的核心机制是 Goroutine 协程、Channel 通道,并基于CSP(Communicating Sequential Processes࿰…...
Web 架构之 CDN 加速原理与落地实践
文章目录 一、思维导图二、正文内容(一)CDN 基础概念1. 定义2. 组成部分 (二)CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 (三)CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 …...
在web-view 加载的本地及远程HTML中调用uniapp的API及网页和vue页面是如何通讯的?
uni-app 中 Web-view 与 Vue 页面的通讯机制详解 一、Web-view 简介 Web-view 是 uni-app 提供的一个重要组件,用于在原生应用中加载 HTML 页面: 支持加载本地 HTML 文件支持加载远程 HTML 页面实现 Web 与原生的双向通讯可用于嵌入第三方网页或 H5 应…...
NXP S32K146 T-Box 携手 SD NAND(贴片式TF卡):驱动汽车智能革新的黄金组合
在汽车智能化的汹涌浪潮中,车辆不再仅仅是传统的交通工具,而是逐步演变为高度智能的移动终端。这一转变的核心支撑,来自于车内关键技术的深度融合与协同创新。车载远程信息处理盒(T-Box)方案:NXP S32K146 与…...
