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 相关文章推荐
Google Dart编程语法和基本类型学习教程
Nov 27 Javascript
JS使用replace()方法和正则表达式进行字符串的搜索与替换实例
Apr 10 Javascript
javascript常用的正则表达式实例
May 15 Javascript
JavaScript实现点击自动选择TextArea文本的方法
Jul 02 Javascript
关于两个jQuery(js)特效冲突的bug的解决办法
Sep 04 Javascript
jQuery实现花式轮播之圣诞节礼物传送效果
Dec 25 Javascript
正则 js分转元带千分符号详解
Mar 08 Javascript
vue 系列——vue2-webpack2框架搭建踩坑之路
Dec 22 Javascript
VUE预渲染及遇到的坑
Sep 03 Javascript
浅谈vue-router路由切换 组件重用挖下的坑
Nov 01 Javascript
Vue列表循环从指定下标开始的多种解决方案
Apr 08 Javascript
ES2020让代码更优美的运算符 (?.) (??)
Jan 04 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 session 检测和注销
2009/03/16 PHP
php 文件上传后缀名与文件类型对照表(几乎涵盖所有文件)
2010/05/16 PHP
PHP输出时间差函数代码
2013/01/28 PHP
在smarty中调用php内置函数的方法
2013/02/07 PHP
浅析PHP程序防止ddos,dns,集群服务器攻击的解决办法
2013/06/18 PHP
使用PHP生成二维码的两种方法(带logo图像)
2014/03/14 PHP
PHP把数字转成人民币大写的函数分享
2014/06/30 PHP
php支付宝在线支付接口开发教程
2016/09/19 PHP
php UNIX时间戳用法详解
2017/02/16 PHP
thinkPHP框架中layer.js的封装与使用方法示例
2019/01/18 PHP
PHP观察者模式定义与用法实例分析
2019/03/22 PHP
PHP底层运行机制与工作原理详解
2020/07/31 PHP
使用IE6看老赵的博客 jQuery初探
2010/01/17 Javascript
javaScript同意等待代码实现心得
2011/01/01 Javascript
Jquery事件的连接使用示例
2013/06/18 Javascript
了解了这些才能开始发挥jQuery的威力
2013/10/10 Javascript
JavaScript中字符串(string)转json的2种方法
2015/06/25 Javascript
详解Angular 4.x NgIf 的用法
2017/05/22 Javascript
浅谈JS如何实现真正的对象常量
2017/06/25 Javascript
在vue项目中使用Jquery-contextmenu插件的步骤讲解
2019/01/27 jQuery
详解JavaScript中的函数、对象
2019/04/01 Javascript
详解Python编程中对Monkey Patch猴子补丁开发方式的运用
2016/05/27 Python
python多进程控制学习小结
2018/10/31 Python
python实现五子棋游戏
2019/06/18 Python
在Python中等距取出一个数组其中n个数的实现方式
2019/11/27 Python
Django restframework 框架认证、权限、限流用法示例
2019/12/21 Python
利用jupyter网页版本进行python函数查询方式
2020/04/14 Python
Python PyQt5模块实现窗口GUI界面代码实例
2020/05/12 Python
Django执行源生mysql语句实现过程解析
2020/11/12 Python
详解CSS中iconfont的使用
2015/08/04 HTML / CSS
中学生英语演讲稿
2014/04/26 职场文书
企业2014年度工作总结
2014/12/10 职场文书
追悼会答谢词
2015/01/05 职场文书
2015年中学校长工作总结
2015/05/19 职场文书
合同审查法律意见书
2015/06/04 职场文书
迎国庆主题班会
2015/08/17 职场文书