惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

P
Palo Alto Networks Blog
N
Netflix TechBlog - Medium
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
小众软件
小众软件
WordPress大学
WordPress大学
宝玉的分享
宝玉的分享
B
Blog
MyScale Blog
MyScale Blog
Microsoft Security Blog
Microsoft Security Blog
aimingoo的专栏
aimingoo的专栏
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Hugging Face - Blog
Hugging Face - Blog
S
Schneier on Security
Project Zero
Project Zero
T
Tenable Blog
T
Tor Project blog
U
Unit 42
G
GRAHAM CLULEY
N
News and Events Feed by Topic
P
Proofpoint News Feed
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Y
Y Combinator Blog
C
Cybersecurity and Infrastructure Security Agency CISA
腾讯CDC
博客园 - 叶小钗
M
MIT News - Artificial intelligence
Vercel News
Vercel News
T
Threat Research - Cisco Blogs
D
Darknet – Hacking Tools, Hacker News & Cyber Security
T
The Exploit Database - CXSecurity.com
P
Privacy & Cybersecurity Law Blog
I
Intezer
博客园 - 聂微东
SecWiki News
SecWiki News
Scott Helme
Scott Helme
C
Cyber Attacks, Cyber Crime and Cyber Security
IT之家
IT之家
量子位
S
Secure Thoughts
The Cloudflare Blog
博客园 - 司徒正美
Know Your Adversary
Know Your Adversary
Hacker News: Ask HN
Hacker News: Ask HN
V
Vulnerabilities – Threatpost
Simon Willison's Weblog
Simon Willison's Weblog
N
News | PayPal Newsroom
C
Check Point Blog
Spread Privacy
Spread Privacy
C
CXSECURITY Database RSS Feed - CXSecurity.com
Cyberwarzone
Cyberwarzone

张鑫旭-鑫空间-鑫生活

1分钟速度了解text-align match-parent声明 « 张鑫旭-鑫空间-鑫生活 光标的形状也能设置了,就是CSS caret-shape属性 « 张鑫旭-鑫空间-鑫生活 pretext与文字四面环绕效果的实现 « 张鑫旭-鑫空间-鑫生活 JSON.rawJSON方法的作用是什么? « 张鑫旭-鑫空间-鑫生活 如何使用CSS判断鼠标从哪个方向进入元素? « 张鑫旭-鑫空间-鑫生活 借助mediabunny纯JS实现视频水印、剪裁、合成等功能 « 张鑫旭-鑫空间-鑫生活 务必谨慎使用JS WeakRef弱引用 « 张鑫旭-鑫空间-鑫生活 CSS六边形头像的实现与蜂巢布局 « 张鑫旭-鑫空间-鑫生活 CSS corner-shape与背景底纹技术 « 张鑫旭-鑫空间-鑫生活 浅学WebTransport API:下一代Web双向通信技术 « 张鑫旭-鑫空间-鑫生活 HTML dialog元素新支持了closedBy属性 « 张鑫旭-鑫空间-鑫生活 HTML interestfor属性与悬停popover交互效果 « 张鑫旭-鑫空间-鑫生活 CSS3模拟window7炫酷界面效果展示 « 张鑫旭-鑫空间-鑫生活 图片旋转+剪裁js插件(兼容各浏览器) « 张鑫旭-鑫空间-鑫生活 纯js无图片无外链CSS图片幻灯片播放插件 « 张鑫旭-鑫空间-鑫生活 CSS border三角、圆角图形生成技术简介 « 张鑫旭-鑫空间-鑫生活 CSS “渐进增强”在web制作中常见应用举例 « 张鑫旭-鑫空间-鑫生活 让IE6/IE7/IE8浏览器支持CSS3属性 « 张鑫旭-鑫空间-鑫生活 jQuery – 高亮动态显示页面HTML代码插件 « 张鑫旭-鑫空间-鑫生活 翻译 – 逐渐消失的Flash网站 « 张鑫旭-鑫空间-鑫生活 CSS reset的重新审视 – 避免样式重置 « 张鑫旭-鑫空间-鑫生活 新浪微博插入话题后部分文字选中的js实现 « 张鑫旭-鑫空间-鑫生活 JavaScript实现http地址自动检测并添加URL链接 « 张鑫旭-鑫空间-鑫生活 CSS实现兼容性的渐变背景(gradient)效果 « 张鑫旭-鑫空间-鑫生活 CSS content内容生成技术以及应用 « 张鑫旭-鑫空间-鑫生活 CSS gradient渐变之webkit核心浏览器下的使用 « 张鑫旭-鑫空间-鑫生活 CSS渐变之CSS3 gradient在Firefox3.6下的使用 « 张鑫旭-鑫空间-鑫生活 区分IE8/IE7/IE6及其他浏览器-CSS “\9″hack « 张鑫旭-鑫空间-鑫生活 CSS实现跨浏览器兼容性的盒阴影效果 « 张鑫旭-鑫空间-鑫生活 CSS3&HTML5各浏览器支持情况一览表 « 张鑫旭-鑫空间-鑫生活 翻译 – CSS Sprites:实用技术还是生厌之物? « 张鑫旭-鑫空间-鑫生活 纯CSS实现易拉罐3D滚动效果 « 张鑫旭-鑫空间-鑫生活 纯CSS实现侧边栏/分栏高度自动相等 « 张鑫旭-鑫空间-鑫生活 CSS+JavaScript实现页面不同布局的切换 « 张鑫旭-鑫空间-鑫生活 JavaScript实现最简单的拖拽效果 « 张鑫旭-鑫空间-鑫生活 自己写的无图片版jQuery zxxbox弹出框插件 « 张鑫旭-鑫空间-鑫生活 中国古代道家思想与网页重构的思考 « 张鑫旭-鑫空间-鑫生活 让所有浏览器支持HTML5 video视频标签 « 张鑫旭-鑫空间-鑫生活 纯CSS实现各类气球泡泡对话框效果 « 张鑫旭-鑫空间-鑫生活 JS HEX十六进制与RGB, HSL颜色的相互转换 « 张鑫旭-鑫空间-鑫生活 CSS实现兼容性的渐变、高光等文字效果 « 张鑫旭-鑫空间-鑫生活 去除冗余 – 精简您的CSS样式代码 « 张鑫旭-鑫空间-鑫生活 对overflow与zoom”清除浮动”的一些认识 « 张鑫旭-鑫空间-鑫生活 jQuery Pagination Ajax分页插件中文详解 « 张鑫旭-鑫空间-鑫生活 absolute绝对定位的非绝对定位用法 « 张鑫旭-鑫空间-鑫生活 网页布局思想浅议-淘宝新版首页为实例 « 张鑫旭-鑫空间-鑫生活 回流与重绘:CSS性能让JavaScript变慢? « 张鑫旭-鑫空间-鑫生活 CSS float浮动的深入研究、详解及拓展(二) « 张鑫旭-鑫空间-鑫生活 CSS float浮动的深入研究、详解及拓展(一) « 张鑫旭-鑫空间-鑫生活 60个极富创造性的震撼的电影海报设计 « 张鑫旭-鑫空间-鑫生活 jQuery Lightbox(balupton版)图片展示插件讲解 « 张鑫旭-鑫空间-鑫生活 博客内嵌flash音乐播放器代码、下载与使用 « 张鑫旭-鑫空间-鑫生活 CSS3 animate实现图片墙3D翻转效果 « 张鑫旭-鑫空间-鑫生活 图片旋转效果的一些研究、jQuery插件及实例 « 张鑫旭-鑫空间-鑫生活 CSS3 border-image详解、应用及jQuery插件 « 张鑫旭-鑫空间-鑫生活 jQuery-两款不同原理的圆角插件讲解 « 张鑫旭-鑫空间-鑫生活 页面可用性之outline轮廓外框的一些研究 « 张鑫旭-鑫空间-鑫生活 CSS3 transition实现超酷图片墙动画效果 « 张鑫旭-鑫空间-鑫生活 HTML CSS列表元素ul,ol,dl的研究与应用 « 张鑫旭-鑫空间-鑫生活 jQuery图片文本滚动切换插件jCarousel中文翻译与详解 « 张鑫旭-鑫空间-鑫生活 酷酷的jQuery鼠标悬停图片放大切换显示效果 « 张鑫旭-鑫空间-鑫生活 IE6下z-index犯癫不起作用bug的初步研究 « 张鑫旭-鑫空间-鑫生活 checkbox复选框的一些深入研究与理解 « 张鑫旭-鑫空间-鑫生活 jQuery之使用slideToggle实现垂直下拉菜单 « 张鑫旭-鑫空间-鑫生活 jQuery-innerfade内部列表自动淡入淡出插件 « 张鑫旭-鑫空间-鑫生活 jQuery-火焰灯效果导航菜单 « 张鑫旭-鑫空间-鑫生活 IE下css bug集合-翻译自haslayout.net « 张鑫旭-鑫空间-鑫生活 翻译-IE7/8@font-face嵌入字体与文字平滑 « 张鑫旭-鑫空间-鑫生活 jQuery-马化腾产品设计与用户体验的一些技术实现 « 张鑫旭-鑫空间-鑫生活 像素的世界及其在web开发制作中的应用 « 张鑫旭-鑫空间-鑫生活 css行高line-height的一些深入理解及应用 « 张鑫旭-鑫空间-鑫生活 CSS实现圆角六色渐变自适应按钮详解 « 张鑫旭-鑫空间-鑫生活 我熟知的三种三栏网页宽度自适应布局方法 « 张鑫旭-鑫空间-鑫生活 jQuery照片图像剪裁插件Jcrop中文翻译详解 « 张鑫旭-鑫空间-鑫生活 Ajax Upload多文件上传插件翻译及中文演示 « 张鑫旭-鑫空间-鑫生活 告别图片—使用字符实现兼容性的圆角尖角效果beta版 « 张鑫旭-鑫空间-鑫生活 大小不固定的图片、多行文字的水平垂直居中 « 张鑫旭-鑫空间-鑫生活 jQuery boxy弹出层对话框插件中文演示及讲解 « 张鑫旭-鑫空间-鑫生活 JavaScript实现新浪微博文字放大显示动画效果 « 张鑫旭-鑫空间-鑫生活 翻译:让网络更快一些——最小化浏览器中的回流(reflow) « 张鑫旭-鑫空间-鑫生活 jQuery之addClasas与removeClass使用实例 « 张鑫旭-鑫空间-鑫生活 关于Google圆角高光高宽自适应按钮及其拓展 « 张鑫旭-鑫空间-鑫生活 JavaScript实现图片幻灯片滚动播放动画效果 « 张鑫旭-鑫空间-鑫生活 jQuery-鼠标经过显示大图并跟随鼠标效果插件 « 张鑫旭-鑫空间-鑫生活 关于gif图片(或png8)杂边锯齿的问题 « 张鑫旭-鑫空间-鑫生活 对html与body的一些研究与理解 « 张鑫旭-鑫空间-鑫生活 鲜为人知的一个解决兼容性问题的利器——小数 « 张鑫旭-鑫空间-鑫生活 搜狐白社会似iphone短信对话框效果的优化 « 张鑫旭-鑫空间-鑫生活 关于文字内容溢出用点点点(…)省略号表示 « 张鑫旭-鑫空间-鑫生活 jquery之append与insertBefore使用实例 « 张鑫旭-鑫空间-鑫生活 jQuery之图片关联伸缩效果 « 张鑫旭-鑫空间-鑫生活 jquery之图片左右切换动画效果 « 张鑫旭-鑫空间-鑫生活 jQuery之replace字符串替换实现不同尺寸图片切换 « 张鑫旭-鑫空间-鑫生活 jQuery-实现图片的放大镜显示效果 « 张鑫旭-鑫空间-鑫生活 jQuery-单击文字或图片内容放大显示效果插件 « 张鑫旭-鑫空间-鑫生活 reflection.js-实现图片投影倒影效果js插件 « 张鑫旭-鑫空间-鑫生活 jQuery-很酷的弹出层效果js插件 « 张鑫旭-鑫空间-鑫生活 复选框单选框与文字对齐问题的研究与解决 « 张鑫旭-鑫空间-鑫生活 css margin的相关属性,问题及应用 « 张鑫旭-鑫空间-鑫生活 IE6下png背景不透明问题的综合拓展 « 张鑫旭-鑫空间-鑫生活
又get到了,JS复制图片到剪切板 « 张鑫旭-鑫空间-鑫生活
张鑫旭,zhangxinxu · 2023-09-17 · via 张鑫旭-鑫空间-鑫生活

by zhangxinxu from https://www.zhangxinxu.com/wordpress/?p=11015 鑫空间-鑫生活
本文欢迎分享与聚合,全文转载就不必了,尊重版权,圈子就这么大,若急用可以联系授权。

封面图 鳐鱼

一、总要有原因的

为什么会突然想到了解如何使用JS复制图片到剪切板呢?

因为上周弄了个PNG/JP在线压缩的工具,一开始的时候,图片获取的途径只能是下载到本地。

但很多时候,我是希望这种压缩好的图片可以直接上传,不需要再从本地转一圈。

此时,如果有一个复制功能就好了。

直接点击一个按钮,压缩好的图片复制到剪切板,然后再去上传页面进行上传,多方便,多轻松。

所以,就去了解了下,还是学到了不少东西的。

这里和大家分享下。

首先,先从简单的开始。

二、原生的图片复制API

浏览器提供了一个名为 ClipboardItem 的实例对象,可以构造构造剪切板复制对象。

例如一段文本的复制(代码取自MDN文档):

function setClipboard(text) {
  const type = "text/plain";
  const blob = new Blob([text], { type });
  const data = [new ClipboardItem({ [type]: blob })];

  navigator.clipboard.write(data).then(() => {
    /* success */
  }, () => {
    /* failure */
  });
}

图片也不在话下。

我专门写了个复制图片的方法,参数就是页面中的IMG元素对象。

const doCopyImg2Clipboard = async (image, success = () => {}, failure = () => {}) => {
    if (!image || !image.src) {
        return;    
    }
    
    // 需要复制的图片的地址
    const src = image.src;
    // 请求该地址,返回图片的blob数据
    const response = await fetch(src);
    
    // 需要是blob数据格式
    const blob = response.blob();
    
    // 使用剪切板API进行复制
    const data = [new ClipboardItem({
        [blob.type || 'image/' + src.split('.').slice(-1)[0].replace('jpg', 'jpeg')]: blob    
    })];
    
    navigator.clipboard.write(data).then(success, failure);
}

如果你已经有了图片的数据(例如本地上传、拖拽或粘贴的图片),则fetch步骤可以略过。

所以,当页面中有如下所示的HTML代码(一张图,一个按钮):

<button id="button" type="primary">复制图片</button>
<img id="image" src="./mybook.jpg">

就可以使用一个简单的点击事件,触发图片的复制了。

例如:

// 点击按钮进行复制
button.addEventListener('click', () => {
    doCopyImg2Clipboard(image, function () {
        new LightTip('复制成功', 'success');
    }, function (err) {
        new LightTip('复制失败:' + err, 'error');
    });
});

然而,上面的代码得到的结果却是失败!

复制失败

从上面的错误提示可以看出,浏览器是不支持 jpg 格式的图片信息写入剪切板的。

试试PNG呢?

如果我们把图片的JPG格式,转换为PNG格式,再试一试,比方说:

<button id="button" type="primary">复制图片</button>
<img id="image" src="./mybook.png">

则就可以成功复制!

眼见为实,您可以狠狠地点击这里:复制JPG和PNG图片到剪切板是否成功demo

比方说,我们点击demo右侧的那个按钮,此时,提示的就会是复制成功,如下截图示意。

复制成功提示

此时,PNG图片信息就已经在剪切板中了。

我们可以找个富文本输入框,或者在线文档编辑器等进行测试。

例如demo页面提供的输入框,我们执行下Ctrl+V,则可以看到图片出现了,如下图所示。

复制粘贴到输入框

OK,好,下面问题来了,页面中有些图片他就是JPG格式的,我非要复制,有没有什么办法呢?

三、JPG/WebP图片的解决之道

要想让JPG或者webp格式的图片也支持剪切板复制,很简单,转为PNG无损图就好了呀。

例如,绘制在canvas上,再使用canvas的toBlob()方法转一下就噢啦。

所以,上面提供的复制代码,我们还可以进一步增强下。

完整JS代码如下所示。

const doCopyImg2Clipboard = async (image, success = () => {}, failure = () => {}) => {
    if (!image || !image.src) {
        return;    
    }
    
    // 原图尺寸
    const { naturalWidth, naturalHeight } = image;
    
    if (!naturalWidth) {
        failure('图片尚未成功加载');
        
        return;
    }
    
    // 绘制图片到canvas上
    const canvas = document.createElement('canvas');
    canvas.width = naturalWidth;
    canvas.height = naturalHeight;
    // canvas绘制上下文
    const context = canvas.getContext('2d');
    // 图片绘制
    context.drawImage(image, 0, 0, naturalWidth, naturalHeight);
    // 转为Blob数据
    canvas.toBlob(blob => {
        // 使用剪切板API进行复制
        const data = [new ClipboardItem({
            ['image/png']: blob    
        })];
        
        navigator.clipboard.write(data).then(success, failure);
    });
}

此时,无论是JPG图片还是WebP图片都可以复制到剪切板了。

doCopyImg2Clipboard(image, function () {
    console.log('复制成功');
});

有演示页面可以体验,您可以狠狠地点击这里:JS复制JPG图片到剪切板demo

复制JPG图片

然而,虽然图片复制了,但是变成PNG之后,原本尺寸适合的JPG图片尺寸就会变得很大。

那图片等于白压缩了。

所以,如果希望复制JPG图片的时候,保留该JPG原始的尺寸,该怎么办呢?

四、若想要保留原图尺寸?

解决方法是不是复制blob二进制数据,而是复制表示图片数据的base64字符串。

然后在上传或者粘贴的地方再二次处理。

图片转base64并复制到剪切板

不哔哔,直接看代码,使用FileReader对象将blob数据转为base64。

const doCopyImgBase64Clipboard = (image, success = () => {}, failure = () => {}) => {
    if (!image || !image.src) {
        return;    
    }
    
    // 需要复制的图片的地址
    const src = image.src;
    // 请求该地址,返回图片的blob数据
    fetch(src).then(response => response.blob()).then(blob => {
        // blob数据转base64
        const reader = new FileReader();
        reader.onload = function() {
            navigator.clipboard.writeText(this.result).then(success, failure);
        };
        reader.readAsDataURL(blob) ;
    });
}

其中:

image
表示页面中的IMG元素对象。
success
表示成功的回调
failure
表示失败的回调

此时,就可以点击按钮,一键复制。

base64图片的处理

在这场场景下,复制并不是最难的,因为文本复制有着非常成熟的解决方案,比方说我之前弄了个“极简文字内容剪切板复制”的gitee项目,优点是自带复制成功的交互提示。

也可以使用业界知名的clipboard.js:https://github.com/zenorocha/clipboard.js

难点在于粘贴时候对base64文本的处理,因为处理粘贴文本并不是一个经常会遇到的场景,大多数的前端都缺乏相应的处理经验。

这里,通过两个例子,演示预览和上传的处理。

1. 预览

base64本身就可以作为图片的URL地址,因此,预览相对简单,只要创建个图片DOM元素,然后插入到页面中就好了。

那如何获得剪切板中粘贴的内容呢?有对应的API的,代码示意:

// 在输入框中粘贴
input.addEventListener('paste', event => {
    var paste = event.clipboardData?.getData('text') || '';
});
// 在页面中粘贴
document.addEventListener('paste', event => {
    var paste = event.clipboardData?.getData('text') || '';
});

此时,只要判断 paste 内容匹配 base64 图片格式即可。

以在输入框中粘贴base64图片为例,完整交互JavaScript代码参见:

// 粘贴对base64内容的监控处理
input.addEventListener('paste', event => {
    var clipboardData = event.clipboardData;

    var paste = clipboardData?.getData('text') || '';

    if (!/^data:image\/[a-z]+;base64,/.test(paste)) {
        return;
    }
    
    event.preventDefault();
    
    // 我是范围
    const selection = document.getSelection();
    // 我是选区
    const range = selection.getRangeAt(0);
    // 删除选区内容,
    range.deleteContents();
    // 并替换成图片
    const imgNode = document.createElement('img');
    imgNode.src = paste;
    range.insertNode(imgNode);
    // 光标定位在图片后面
    range.setStartAfter(imgNode);
});

眼见为实,您可以狠狠地点击这里:JS复制图片base64信息到剪切板demo

点击按钮,会复制图片的base64信息,此时,再粘贴到页面中的测试输入框,会发现,显示的不是字符串内容,而是图片,就是因为有上面这段 JS 解析代码。

操作示意

2. 上传

base64图片地址上传有两种解决方法,一是后端判断处理,即,如果post的是二进制数据流,如何处理,如果post的是字符串数据流,又该如何处理。

还有一种方法是在前端处理,将剪切板中的base64字符串转为blob文件数据再上传,这样,后端那边轻松点。

以下代码示意了下如何处理:

// base64 转 blob
const b64toBlob = (b64Data, contentType='', sliceSize=512) =&gt; {
  const byteCharacters = atob(b64Data);
  const byteArrays = [];

  for (let offset = 0; offset &lt; byteCharacters.length; offset += sliceSize) {
    const slice = byteCharacters.slice(offset, offset + sliceSize);

    const byteNumbers = new Array(slice.length);
    for (let i = 0; i &lt; slice.length; i++) {
      byteNumbers[i] = slice.charCodeAt(i);
    }

    const byteArray = new Uint8Array(byteNumbers);
    byteArrays.push(byteArray);
  }

  const blob = new Blob(byteArrays, {type: contentType});
  return blob;
}

// 粘贴base64上传
document.addEventListener('paste', function (event) {
    var clipboardData = event.clipboardData;

    var paste = clipboardData?.getData('text') || '';

    if (!paste.startsWith('data:image')) {
        return;
    }

    // 核心数据
    var base64 = paste.split('base64,')[1];
    // 类型
    var type = paste.split(';base64')[0].replace('data:', '');
    // 获取 blob 数据
    var blob = b64toBlob(base64, type);
    // 设置个文件名,不然是undefined
    blob.name = new Date().toLocaleString().replaceAll('/', '-').replace(/\s/g, '_').replaceAll(':', '') + '.' + (type.split('/')[1] || 'png');

    // 此时的 blob 就是需要上传的文件数据了...
});

于是,整个一套流程就可以走通了。

前端压缩图片,JS复制压缩后的base64字符信息,然后JS解析base64并上传。

结语

时不时给自己找个需求,而不仅仅是业务开发,可能会遇到平常遇不到的场景,积累不一样的经验。

要是下次业务开发遇到类似需求,那就是分分钟上手,开发效率领先一步。

还能撸一篇文章,完成自己给自己制定的平均每周需要一个技术文章输出的KPI。

一劳多得,岂不美哉。

噢啦,以上就是本文的全部内容啦。

希望里面的内容可以对大家的工作学习有所帮助。

如果您觉得不错,欢迎,点赞。

? ? ? ? ?

本文为原创文章,欢迎分享,勿全文转载,如果实在喜欢,可收藏,永不过期,且会及时更新知识点及修正错误,阅读体验也更好。
本文地址:https://www.zhangxinxu.com/wordpress/?p=11015

(本篇完)