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 相关文章推荐
鼠标右击事件代码(asp.net后台)
Jan 27 Javascript
javascript学习笔记(六) Date 日期类型
Jun 19 Javascript
jquery中文乱码的多种解决方法
Jun 21 Javascript
Javascript 实现复制(Copy)动作方法大全
Jun 20 Javascript
浅析Node.js的Stream模块中的Readable对象
Jul 29 Javascript
BootStrap使用popover插件实现鼠标经过显示并保持显示框
Jun 23 Javascript
通过V8源码看一个关于JS数组排序的诡异问题
Aug 14 Javascript
vue用addRoutes实现动态路由的示例
Sep 15 Javascript
vue.js过滤器+ajax实现事件监听及后台php数据交互实例
May 22 Javascript
Javascript 之封装(Package)
Sep 14 Javascript
Element实现表格嵌套、多个表格共用一个表头的方法
May 09 Javascript
前端框架ECharts dataset对数据可视化的高级管理
Dec 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
php日期转时间戳,指定日期转换成时间戳
2012/07/17 PHP
领悟php接口中interface存在的意义
2013/06/27 PHP
php实现mysql数据库操作类分享
2014/02/14 PHP
php类的定义与继承用法实例
2015/07/07 PHP
详解WordPress中分类函数wp_list_categories的使用
2016/01/04 PHP
PHP页面跳转实现延时跳转的方法
2016/12/10 PHP
Laravel框架实现修改登录和注册接口数据返回格式的方法
2018/08/17 PHP
添加到收藏夹代码(兼容几乎所有的浏览器)
2007/01/09 Javascript
JavaScript 笔记二 Array和Date对象方法
2010/05/22 Javascript
jQuery获取css z-index在各种浏览器中的返回值
2010/09/15 Javascript
script标签的 charset 属性使用说明
2010/12/04 Javascript
THREE.JS入门教程(1)THREE.JS使用前了解
2013/01/24 Javascript
10个基于浏览器的JavaScript调试工具分享
2013/02/07 Javascript
jquery打开直接跳到网页最下面、最低端实现代码
2013/04/22 Javascript
jQuery之折叠面板的深入解析
2013/06/19 Javascript
浅析js中substring和substr的方法
2015/11/09 Javascript
使用jquery.qrcode.min.js实现中文转化二维码
2016/03/11 Javascript
BootStrap点击下拉菜单项后显示一个新的输入框实现代码
2016/05/16 Javascript
浅谈JavaScript for循环 闭包
2016/06/22 Javascript
利用Bootstrap实现表格复选框checkbox全选
2016/12/21 Javascript
详解nodejs模板引擎制作
2017/06/14 NodeJs
JavaScript函数式编程(Functional Programming)高阶函数(Higher order functions)用法分析
2019/05/22 Javascript
微信小程序绑定手机号获取验证码功能
2019/10/22 Javascript
vue3.0 上手体验
2020/09/21 Javascript
[01:11:21]DOTA2-DPC中国联赛 正赛 VG vs Elephant BO3 第一场 3月6日
2021/03/11 DOTA
详解Django中的ifequal和ifnotequal标签使用
2015/07/16 Python
Python实现删除时保留特定文件夹和文件的示例
2018/04/27 Python
使用matplotlib画散点图的方法
2018/05/25 Python
django 实现电子支付功能的示例代码
2018/07/25 Python
python编写softmax函数、交叉熵函数实例
2020/06/11 Python
HTML5 body设置自适应全屏
2020/05/07 HTML / CSS
美国唇部护理专家:Sara Happ
2019/06/19 全球购物
企业与个人合作经营协议书
2014/11/01 职场文书
保研导师推荐信
2015/03/25 职场文书
士兵突击观后感
2015/06/16 职场文书
MySQL索引失效的典型案例
2021/06/05 MySQL