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 相关文章推荐
window.open()弹出居中的窗口
Feb 01 Javascript
使用jscript实现二进制读写脚本代码
Jun 09 Javascript
浅谈Javascript嵌套函数及闭包
Nov 09 Javascript
Javascript中定义方法的另类写法(批量定义js对象的方法)
Feb 25 Javascript
javascript使用数组的push方法完成快速排序
Sep 15 Javascript
javascript显示上周、上个月日期的处理方法
Feb 03 Javascript
Javascript实现跑马灯效果的简单实例
May 31 Javascript
Vue.js基础知识小结
Jan 13 Javascript
解决vue打包项目后刷新404的问题
Mar 06 Javascript
javascript中的闭包概念与用法实践分析
Jul 26 Javascript
小程序调用微信支付的方法
Sep 26 Javascript
深入理解webpack process.env.NODE_ENV配置
Feb 23 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 执行系统命令的方法
2009/07/07 PHP
php 生成WML页面方法详解
2009/08/09 PHP
Windows下PHP开发环境搭建教程(Apache+PHP+MySQL)
2016/06/13 PHP
Yii2.0 Basic代码中路由链接被转义的处理方法
2016/09/21 PHP
详解配置 Apache 服务器支持 PHP 文件的解析
2017/02/15 PHP
PHP守护进程化在C和PHP环境下的实现
2017/11/21 PHP
php文件上传原理与实现方法详解
2019/12/20 PHP
IE6中使用position导致页面变形的解决方案(js代码)
2011/01/09 Javascript
解决json日期格式问题的3种方法
2014/02/02 Javascript
一个JavaScript获取元素当前高度的实例
2014/10/29 Javascript
Js制作点击输入框时默认文字消失的效果
2015/09/05 Javascript
JavaScript判断表单为空及获取焦点的方法
2016/02/12 Javascript
js动态添加表格逐行添加、删除、遍历取值的实例代码
2018/01/25 Javascript
AngularJS对动态增加的DOM实现ng-keyup事件示例
2018/03/12 Javascript
在vue和element-ui的table中实现分页复选功能
2019/12/04 Javascript
原生js实现随机点名
2020/07/05 Javascript
[01:20]PWL开团时刻DAY9——听说潮汐没用?
2020/11/10 DOTA
初学Python实用技巧两则
2014/08/29 Python
Python实现建立SSH连接的方法
2015/06/03 Python
Python脚本处理空格的方法
2016/08/08 Python
Python调用C++程序的方法详解
2017/01/24 Python
利用Pandas 创建空的DataFrame方法
2018/04/08 Python
PyTorch快速搭建神经网络及其保存提取方法详解
2018/04/28 Python
python爬取百度贴吧前1000页内容(requests库面向对象思想实现)
2019/08/10 Python
Python实现常见的几种加密算法(MD5,SHA-1,HMAC,DES/AES,RSA和ECC)
2020/05/09 Python
Python调用.net动态库实现过程解析
2020/06/05 Python
Python 3.10 的首个 PEP 诞生,内置类型 zip() 迎来新特性(推荐)
2020/07/03 Python
高校十八大报告感想
2014/01/27 职场文书
经营理念标语
2014/06/21 职场文书
少先队辅导员事迹材料
2014/12/24 职场文书
财务会计求职信范文
2015/03/20 职场文书
2016幼儿园新学期寄语
2015/12/03 职场文书
表扬信范文
2019/04/22 职场文书
Python包管理工具pip的15 个使用小技巧
2021/05/17 Python
Mysql如何实现不存在则插入,存在则更新
2022/03/25 MySQL
Python中的 enumerate和zip详情
2022/05/30 Python