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 相关文章推荐
JQUERY 浏览器判断实现函数
Aug 20 Javascript
替代window.event.srcElement效果的可兼容性的函数
Dec 18 Javascript
JavaScript 数组运用实现代码
Apr 13 Javascript
2010年最佳jQuery插件整理
Dec 06 Javascript
jQuery中extend()和fn.extend()方法详解
Jun 03 Javascript
javascript下使用Promise封装FileReader
Feb 19 Javascript
Vue键盘事件用法总结
Apr 18 Javascript
Angular4开发解决跨域问题详解
Aug 28 Javascript
浅谈Vue.js中ref ($refs)用法举例总结
Dec 19 Javascript
JS实现二维数组横纵列转置的方法
Apr 17 Javascript
vue 解决setTimeOut和setInterval函数无效报错的问题
Jul 30 Javascript
解决vue下载后台传过来的乱码流的问题
Dec 05 Vue.js
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
Gregarius中文日期格式问题解决办法
2008/04/22 PHP
PHP使用flock实现文件加锁的方法
2015/07/01 PHP
简要剖析PHP的Yii框架的组件化机制的基本知识
2016/03/17 PHP
Yii2中如何使用modal弹窗(基本使用)
2016/05/30 PHP
PHP实现简单的计算器
2020/08/28 PHP
日期函数扩展类Ver0.1.1
2006/09/07 Javascript
基于jquery实现的可以编辑选择的下拉框的代码
2010/11/19 Javascript
Jquery下attr和removeAttr的使用方法
2010/12/28 Javascript
修复ie8&amp;chrome下window的resize事件多次执行
2011/10/20 Javascript
js判断样式className同时增加class或删除class
2013/01/30 Javascript
Javascript writable特性介绍
2015/02/27 Javascript
jQuery实现自动调整字体大小的方法
2015/06/15 Javascript
基于javascript实现仿百度输入框自动匹配功能
2016/01/03 Javascript
你所未知的3种Node.js代码优化方式
2016/02/25 Javascript
微信+angularJS的SPA应用中用router进行页面跳转,jssdk校验失败问题解决
2016/09/09 Javascript
深入理解Angular.JS中的Scope继承
2017/06/04 Javascript
mui开发中获取单选按钮、复选框的值(实例讲解)
2017/07/24 Javascript
QQ跳转支付宝并自动领红包脚本(最新)
2018/06/22 Javascript
小程序实现按下录音松开识别语音
2019/11/22 Javascript
[04:59]2018DOTA2亚洲邀请赛 4.7 Mineski夺冠时刻
2018/04/09 DOTA
python:pandas合并csv文件的方法(图书数据集成)
2018/04/12 Python
python执行系统命令后获取返回值的几种方式集合
2018/05/12 Python
在Python中使用defaultdict初始化字典以及应用方法
2018/10/31 Python
python实现转圈打印矩阵
2019/03/02 Python
python中property和setter装饰器用法
2019/12/19 Python
python Manager 之dict KeyError问题的解决
2019/12/21 Python
css3制作动态进度条以及附加jQuery百分比数字显示
2012/12/13 HTML / CSS
PacSun官网:加州生活方式服装、鞋子和配饰
2018/03/10 全球购物
英国和爱尔兰最大的地毯零售商:Kukoon
2018/12/17 全球购物
.NET程序员的几道面试题
2012/06/01 面试题
介绍下Lucene建立索引的过程
2016/03/02 面试题
接受捐赠答谢词
2014/01/27 职场文书
学生党支部先进事迹
2014/02/04 职场文书
交警正风肃纪剖析材料
2014/10/29 职场文书
Android Flutter实现3D动画效果示例详解
2022/04/07 Java/Android
win10输入法不见了只能打出字母怎么解决?
2022/08/05 数码科技