JavaScript 禁止用户保存图片的实现代码


Posted in Javascript onApril 28, 2020

添加事件禁止选择、拖拽、右键(简单的禁止用户保存图片,但无法阻止用户打开控制台查看,或是直接抓包)
将之转换为 canvas(让浏览器认为不是图片以此禁止用户对之进行图片的操作,但无法阻止抓包)
禁止用户使用控制台查看源码(阻止浏览器打开控制台,但无法阻止抓包)
传输图片使用自定义格式(可以阻止抓包,但需要后台配合)

注:以下内容使用 react+ts 实现

添加事件禁止选择、拖拽、右键

简而言之,这是一种简单有效的方式,能够在用户不打开控制台的情况下阻止用户保存图片。

export function preventDefaultListener(e: any) {
 e.preventDefault()
}

;<img
 src={props.url}
 alt=""
 style={{
 //禁止用户选择
 userSelect: 'none',
 //禁止所有鼠标事件,过于强大,图片仅用于展示可用
 // pointerEvents: 'none',
 }}
 onTouchStart={preventDefaultListener}
 onContextMenu={preventDefaultListener}
 onDragStart={preventDefaultListener}
/>

参考:https://3water.com/article/185677.htm

将之转换为 canvas

另一种思路是将图片转换为 canvas 避免用户使用img相关的操作。

将图片转成 canvas

export async function imageToCanvas(url: string, canvas: HTMLCanvasElement) {
 return new Promise((resolve, reject) => {
 //新建Image对象,引入当前目录下的图片
 const img = new Image()
 img.src = url
 const c = canvas.getContext('2d')!

 //图片初始化完成后调用
 img.onload = function () {
  //将canvas的宽高设置为图像的宽高
  canvas.width = img.width
  canvas.height = img.height

  //canvas画图片
  c.drawImage(img, 0, 0, img.width, img.height)
  resolve()
 }
 img.addEventListener('error', (e) => {
  reject(e)
 })
 })
}

禁用 canvas 事件

const throwFn = () => {
 throw new Error(
 "Uncaught DOMException: Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported.",
 )
}

const $canvasRef = useRef<HTMLCanvasElement>(null)
 useEffect(() => {
  ;(async () => {
   await imageToCanvas(props.url, $canvasRef.current!)
   $canvasRef.current!.toBlob = throwFn
   $canvasRef.current!.toDataURL = throwFn
  })()
 }, [])
 return (
  <canvas
   ref={$canvasRef}
   onTouchStart={preventDefaultListener}
   onContextMenu={preventDefaultListener}
  />
 )

禁止用户使用控制台查看源码

如果能禁止用户操作控制台,那么自然能够避免用户查看源码了,下面是一个简单的实现。

/**
 * 兼容异步函数的返回值
 * @param res 返回值
 * @param callback 同步/异步结果的回调函数
 * @typeparam T 处理参数的类型,如果是 Promise 类型,则取出其泛型类型
 * @typeparam Param 处理参数具体的类型,如果是 Promise 类型,则指定为原类型
 * @typeparam R 返回值具体的类型,如果是 Promise 类型,则指定为 Promise 类型,否则为原类型
 * @returns 处理后的结果,如果是同步的,则返回结果是同步的,否则为异步的
 */
export function compatibleAsync<T = any, Param = T | Promise<T>, R = T>(
 res: Param,
 callback: (r: T) => R,
): Param extends Promise<T> ? Promise<R> : R {
 return (res instanceof Promise
 ? res.then(callback)
 : callback(res as any)) as any
}

/**
 * 测试函数的执行时间
 * 注:如果函数返回 Promise,则该函数也会返回 Promise,否则直接返回执行时间
 * @param fn 需要测试的函数
 * @returns 执行的毫秒数
 */
export function timing<R>(
 fn: (...args: any[]) => R,
 // 函数返回类型是 Promise 的话,则返回 Promise<number>,否则返回 number
): R extends Promise<any> ? Promise<number> : number {
 const begin = performance.now()
 const res = fn()
 return compatibleAsync(res, () => performance.now() - begin)
}
/**
 * 禁止他人调试网站相关方法的集合对象
 */
export class AntiDebug {
 /**
 * 不停循环 debugger 防止有人调试代码
 * @returns 取消函数
 */
 public static cyclingDebugger(): Function {
 const res = setInterval(() => {
  debugger
 }, 100)
 return () => clearInterval(res)
 }
 /**
 * 检查是否正在 debugger 并调用回调函数
 * @param fn 回调函数,默认为重载页面
 * @returns 取消函数
 */
 public static checkDebug(
 fn: Function = () => window.location.reload(),
 ): Function {
 const res = setInterval(() => {
  const diff = timing(() => {
  debugger
  })
  if (diff > 500) {
  console.log(diff)
  fn()
  }
 }, 1000)
 return () => clearInterval(res)
 }
}
useEffect(() => {
 const cancel1 = AntiDebug.cyclingDebugger() as any
 const cancel2 = AntiDebug.checkDebug(() =>
 console.log('请不要打开调试'),
 ) as any
 return () => {
 cancel1()
 cancel2()
 }
}, [])

return <img src={url} alt="" />

传输图片使用自定义格式

该功能需要服务端配合,故而此处赞不实现,可以参考微信读书,就是将文本转为 canvas,数据传输也进行了加密,可以在很大程度上防止普通用户想要复制/下载的行为了。

到此这篇关于JavaScript 禁止用户保存图片的文章就介绍到这了,更多相关js 禁止保存图片内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Javascript 相关文章推荐
农历与西历对照
Sep 06 Javascript
json 定义
Jun 10 Javascript
javascript 流畅动画实现原理
Sep 08 Javascript
jquery事件重复绑定的快速解决方法
Jan 03 Javascript
JavaScript中的alert()函数使用技巧详解
Dec 29 Javascript
js实现无限级树形导航列表效果代码
Sep 23 Javascript
基于jQuery实现数字滚动效果
Jan 16 Javascript
js实现仿购物车加减效果
Mar 01 Javascript
vue中eventbus被多次触发以及踩过的坑
Dec 02 Javascript
在Vue中使用Compass的方法
Mar 02 Javascript
深入浅析Vue中mixin和extend的区别和使用场景
Aug 01 Javascript
Vue Router的手写实现方法实现
Mar 02 Javascript
JS求解两数之和算法详解
Apr 28 #Javascript
jQuery插件simplePagination的使用方法示例
Apr 28 #jQuery
uni-app如何页面传参数的几种方法总结
Apr 28 #Javascript
JavaScript 双向链表操作实例分析【创建、增加、查找、删除等】
Apr 28 #Javascript
JS 创建对象的模式实例小结
Apr 28 #Javascript
JavaScript console的使用方法实例分析
Apr 28 #Javascript
Node.js设置定时任务之node-schedule模块的使用详解
Apr 28 #Javascript
You might like
php配置php-fpm启动参数及配置详解
2013/11/04 PHP
php 删除cookie方法详解
2014/12/01 PHP
程序员的表白神器“520”大声喊出来
2016/05/20 PHP
基于jQuery捕获超链接事件进行局部刷新代码
2012/05/10 Javascript
js图片实时加载提供网页打开速度
2014/09/11 Javascript
jQuery中has()方法用法实例
2015/01/06 Javascript
JavaScript限定图片显示大小的方法
2015/03/11 Javascript
微信小程序 WXML、WXSS 和JS介绍及详解
2016/10/08 Javascript
AngularJS中一般函数参数传递用法分析
2016/11/22 Javascript
nodejs的压缩文件模块archiver用法示例
2017/01/18 NodeJs
常用的几个JQuery代码片段
2017/03/13 Javascript
JavaScript生成图形验证码
2020/08/24 Javascript
vue项目中的webpack-dev-sever配置方法
2017/12/14 Javascript
让你5分钟掌握9个JavaScript小技巧
2018/06/09 Javascript
angularJs中$http获取后台数据的实例讲解
2018/08/08 Javascript
vue移动端下拉刷新和上拉加载的实现代码
2018/09/08 Javascript
解决pycharm双击但是无法打开的情况
2020/10/31 Javascript
微信小程序实现点赞业务
2021/02/10 Javascript
[28:05]完美世界DOTA2联赛循环赛Inki vs DeMonsTer 第一场 10月30日
2020/10/31 DOTA
布同自制Python函数帮助查询小工具
2011/03/13 Python
python 中文乱码问题深入分析
2011/03/13 Python
python实现文本进度条 程序进度条 加载进度条 单行刷新功能
2019/07/03 Python
Django中自定义查询对象的具体使用
2019/10/13 Python
python 爬取免费简历模板网站的示例
2020/09/27 Python
HTML5 实现图片上传预处理功能
2020/02/06 HTML / CSS
AmazeUI折叠式卡片布局,整合内容列表、表格组件实现
2020/08/20 HTML / CSS
西班牙网上书店:Casa del Libro
2016/11/01 全球购物
台湾菁英交友:结识黄金单身的台湾人
2018/01/22 全球购物
French Connection官网:女装、男装及家居用品
2019/03/18 全球购物
财务会计实习报告体会
2013/12/20 职场文书
高速铁道技术专业求职信
2014/08/09 职场文书
出租车拒载检讨书
2015/01/28 职场文书
施工现场安全管理制度
2015/08/05 职场文书
创业计划书之溜冰场
2019/10/25 职场文书
vue route新窗口跳转页面并且携带与接收参数
2022/04/10 Vue.js
Win10多屏显示如何设置?Win10电脑多屏显示设置操作方法
2022/07/07 数码科技