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 相关文章推荐
Javascript与vbscript数据共享
Jan 09 Javascript
解决jquery异步按一定的时间间隔刷新问题
Dec 10 Javascript
jQuery EasyUI 布局之动态添加tabs标签页
Nov 18 Javascript
jQuery输入框密码的显示隐藏【代码分享】
Apr 29 jQuery
jQuery、layer实现弹出层的打开、关闭功能
Jun 28 jQuery
bootstrap table实现x-editable的行单元格编辑及解决数据Empty和支持多样式问题
Aug 10 Javascript
新手入门带你学习JavaScript引擎运行原理
Jun 24 Javascript
微信小程序登录对接Django后端实现JWT方式验证登录详解
Jul 29 Javascript
JavaScript设计模式之观察者模式与发布订阅模式详解
May 07 Javascript
JavaScript中使用Spread运算符的八种方法总结
Jun 18 Javascript
JS sort方法基于数组对象属性值排序
Jul 10 Javascript
Nuxt的动态路由和参数校验操作
Nov 09 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
DC游戏Steam周三特惠 《蝙蝠侠》阿卡姆系列平史低
2020/04/09 欧美动漫
关于Iframe如何跨域访问Cookie和Session的解决方法
2013/04/15 PHP
php编程实现简单的网页版计算器功能示例
2017/04/26 PHP
PHP的mysqli_select_db()函数讲解
2019/01/23 PHP
Laravel框架中缓存的使用方法分析
2019/09/06 PHP
详解no input file specified 三种解决方法
2019/11/29 PHP
javascript实现的listview效果
2007/04/28 Javascript
jquery 使用点滴函数代码
2011/05/20 Javascript
jquery获取选中的文本和值的方法
2014/07/08 Javascript
javascript跨域的方法汇总
2015/10/23 Javascript
Jquery1.9.1源码分析系列(十五)动画处理之外篇
2015/12/04 Javascript
关于vue.js过渡css类名的理解(推荐)
2017/04/10 Javascript
Angular2学习教程之组件中的DOM操作详解
2017/05/28 Javascript
vue webuploader 文件上传组件开发
2017/09/23 Javascript
Vue的事件响应式进度条组件实例详解
2018/02/04 Javascript
微信小程序实现自定义modal弹窗封装的方法
2018/06/15 Javascript
详解基于DllPlugin和DllReferencePlugin的webpack构建优化
2018/06/28 Javascript
vue实现双向绑定和依赖收集遇到的坑
2018/11/29 Javascript
vue3.0生命周期的示例代码
2020/09/24 Javascript
对python_discover方法遍历所有执行的用例详解
2019/02/13 Python
python实现图书借阅系统
2019/02/20 Python
python求质数列表的例子
2019/11/24 Python
python网络编程:socketserver的基本使用方法实例分析
2020/04/09 Python
HTML5之SVG 2D入门10—滤镜的定义及使用
2013/01/30 HTML / CSS
Fossil美国官网:化石手表、手袋、首饰及配饰
2019/02/17 全球购物
linux面试题参考答案(2)
2015/12/06 面试题
出国留学自荐信
2013/10/25 职场文书
行政前台岗位职责
2013/12/04 职场文书
上课迟到检讨书
2014/02/19 职场文书
《鞋匠的儿子》教学反思
2014/03/02 职场文书
超市促销活动总结
2014/07/01 职场文书
人身损害赔偿协议书范本
2014/09/27 职场文书
企业愿景口号
2015/12/25 职场文书
简历自我评价范文
2019/04/24 职场文书
JavaScript 防篡改对象的用法示例
2021/04/24 Javascript
python基础学习之递归函数知识总结
2021/05/26 Python