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 相关文章推荐
动态改变textbox的宽高的js
Oct 26 Javascript
Javascript 面向对象(三)接口代码
May 23 Javascript
分享一个常用的javascript静态类
Dec 31 Javascript
jquery拖拽效果完整实例(附demo源码下载)
Jan 14 Javascript
JS动态插入并立即执行回调函数的方法
Apr 21 Javascript
Bootstrap基本插件学习笔记之轮播幻灯片(23)
Dec 08 Javascript
jQuery Ajax 实现在html页面实时显示用户登录状态
Dec 30 Javascript
jQuery事件_动力节点Java学院整理
Jul 05 jQuery
基于jQuery实现定位导航位置效果
Nov 15 jQuery
vue中使用echarts制作圆环图的实例代码
Jul 27 Javascript
JS立即执行的匿名函数用法分析
Nov 04 Javascript
微信小程序swiper组件实现抖音翻页切换视频功能的实例代码
Jun 24 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
WordPress开发中用于获取近期文章的PHP函数使用解析
2016/01/05 PHP
PHP7 echo和print语句实例用法
2019/02/15 PHP
php使用event扩展的io复用测试的示例
2020/10/20 PHP
扩展easyui.datagrid,添加数据loading遮罩效果代码
2010/11/02 Javascript
jQuery 追加元素的方法如append、prepend、before
2014/01/16 Javascript
js字符串日期yyyy-MM-dd转化为date示例代码
2014/03/06 Javascript
js获取及修改网页背景色和字体色的方法
2015/12/29 Javascript
zepto与jquery的区别及zepto的不同使用8条小结
2016/07/28 Javascript
基于iscroll.js实现下拉刷新和上拉加载效果
2016/11/28 Javascript
浅谈js for循环输出i为同一值的问题
2017/03/01 Javascript
高性能的javascript之加载顺序与执行原理篇
2018/01/14 Javascript
nodeJs实现基于连接池连接mysql的方法示例
2018/02/10 NodeJs
AngularJS select加载数据选中默认值的方法
2018/02/28 Javascript
浅谈vue.js导入css库(elementUi)的方法
2018/03/09 Javascript
nodejs简单访问及操作mysql数据库的方法示例
2018/03/15 NodeJs
微信小程序实现多选框全选与取消全选功能示例
2019/05/14 Javascript
js实现简单掷骰子效果
2019/10/24 Javascript
JS如何在不同平台实现多语言方式
2020/07/16 Javascript
遍历python字典几种方法总结(推荐)
2016/09/11 Python
Python中字符串的修改及传参详解
2016/11/30 Python
Python 判断是否为质数或素数的实例
2017/10/30 Python
PyQt5实现五子棋游戏(人机对弈)
2020/03/24 Python
python装饰器简介---这一篇也许就够了(推荐)
2019/04/01 Python
在Python中os.fork()产生子进程的例子
2019/08/08 Python
10行Python代码计算汽车数量的实现方法
2019/10/23 Python
Python jieba库用法及实例解析
2019/11/04 Python
K最近邻算法(KNN)---sklearn+python实现方式
2020/02/24 Python
使用OpenCV获取图像某点的颜色值,并设置某点的颜色
2020/06/02 Python
金山毒霸系列的笔试题
2013/04/13 面试题
《鱼游到了纸上》教学反思
2014/02/20 职场文书
婚礼司仪主持词
2014/03/14 职场文书
小学清明节活动总结
2014/07/04 职场文书
勇敢的心观后感
2015/06/09 职场文书
关于销售人员的年终工作总结要点
2019/08/15 职场文书
go 原生http web 服务跨域restful api的写法介绍
2021/04/27 Golang
delete in子查询不走索引问题分析
2022/07/07 MySQL