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与asp.net(c#)互相调用方法
Dec 13 Javascript
extjs tabpanel限制选项卡数量实现思路及代码
Apr 02 Javascript
使用jquery实现IE下按backspace相当于返回操作
Mar 18 Javascript
JavaScript实现图片懒加载(Lazyload)
Nov 28 Javascript
COM组件中调用JavaScript函数详解及实例
Feb 23 Javascript
详解Vue-cli中的静态资源管理(src/assets和static/的区别)
Jun 19 Javascript
Vue filter格式化时间戳时间成标准日期格式的方法
Sep 16 Javascript
JS中数组实现代码(倒序遍历数组,数组连接字符串)
Dec 29 Javascript
JS 创建对象的模式实例小结
Apr 28 Javascript
JS轮播图的实现方法
Aug 24 Javascript
jQuery使用hide()、toggle()函数实现相机品牌展示隐藏功能
Jan 29 jQuery
原生JavaScript实现进度条
Feb 19 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中批量修改文件后缀名的函数代码
2011/10/23 PHP
PHP制作百度词典查词采集器
2015/01/29 PHP
关于eval 与new Function 到底该选哪个?
2013/04/17 Javascript
Jquery的Tabs内容轮换效果实现代码,几行搞定
2014/02/12 Javascript
JavaScript获得页面base标签中url的方法
2015/04/03 Javascript
js删除局部变量的实现方法
2016/06/25 Javascript
AngularJS 实现JavaScript 动画效果详解
2016/09/08 Javascript
详解AngularJS ui-sref的简单使用
2017/04/24 Javascript
vue移动端UI框架实现QQ侧边菜单组件
2018/03/09 Javascript
Vue页面骨架屏注入方法
2018/05/13 Javascript
JS实现图片旋转动画效果封装与使用示例
2018/07/09 Javascript
微信小程序实现多选功能
2018/11/04 Javascript
学习使用ExpressJS 4.0中的新Router的用法
2018/11/06 Javascript
vue组件文档(.md)中如何自动导入示例(.vue)详解
2019/01/25 Javascript
使用Layui搭建后台管理界面的操作方法
2019/09/20 Javascript
基于 Vue 的 Electron 项目搭建过程图文详解
2020/07/22 Javascript
详解JavaScript 的执行机制
2020/09/18 Javascript
vuex的使用步骤
2021/01/06 Vue.js
[01:08:10]2014 DOTA2国际邀请赛中国区预选赛 SPD-GAMING VS LGD-CDEC
2014/05/22 DOTA
[01:08:00]Fnatic vs Winstrike 2018国际邀请赛小组赛BO2 第一场 8.18
2018/08/19 DOTA
如何搜索查找并解决Django相关的问题
2014/06/30 Python
简单说明Python中的装饰器的用法
2015/04/24 Python
python中退出多层循环的方法
2018/11/27 Python
在VS2017中用C#调用python脚本的实现
2019/07/31 Python
Python Tornado之跨域请求与Options请求方式
2020/03/28 Python
tensorflow下的图片标准化函数per_image_standardization用法
2020/06/30 Python
通过代码实例了解Python sys模块
2020/09/14 Python
python 装饰器的基本使用
2021/01/13 Python
瑞典手机壳品牌:Richmond & Finch
2018/04/28 全球购物
SHEIN台湾:购买最新流行女装服饰
2019/05/18 全球购物
保安员岗位职责
2013/11/17 职场文书
创建精神文明单位实施方案
2014/03/08 职场文书
家长写给老师的建议书
2014/03/13 职场文书
自我推荐信范文
2014/05/09 职场文书
2016年小学植树节活动总结
2016/03/16 职场文书
为什么代码规范要求SQL语句不要过多的join
2021/06/23 MySQL