js实现复制二维码
1.介绍
项目中有一个二维码复制功能,首先是根据所选择的组织与邀请成为的角色,后端返回一个二维码数据链接,将二维码渲染展示在页面上;然后在点击复制按钮时可以复制二维码,在其它的地方可以直接粘贴使用。复制二维码还不是简单的复制二维码图片,而是还要加上一些其它的描述西信息,如邀请进行的项目、邀请到的组织、邀请成为的角色等,这些信息和二维码一起转成一个图片进行复制。
2.思路
思路一:document.execCommand。查文档发现已废弃,所以不考虑。
https://juejin.cn/post/6909237803050074126
思路二:开源库(clipboard.js)。经验证也不适合
1.这个库依赖的 document.execCommand API 已被废弃了 ;
2.这个库只支持文字的复制;(文字复制时推荐这个库);
思路三:Clipboard API 。可用,但是有一些限制。
3.Clipboard API实现复制
https://developer.mozilla.org/zh-CN/docs/Web/API/ClipboardItem
局限:由于新版浏览器的安全策略,clipboard只有在安全域名下才可以访问,http域名下会显示undefined,但使用https开头的域名,或localhost,就可以访问navigator.clipboard。所以使用此API必须是在https安全协议访问或localhost本地安全访问。
步骤:
1.生成一个整体HTML元素,渲染在页面上同时不让用户看到。
这里这么做的原因是因为后续要使用dom-to-image将该元素转为blob数据,如果不渲染在页面上,最后复制出的图片是一个空白页;
这里还有一个坑,这个整体元素不能使用绝对定位,否则复制出的图片仍是一个空白页,不知道为什么。所以这里使用了相对定位,给相对定位加z-index进行不可见。
<div class="copy-content flex flex-col items-center" :style="`display:${copyclick?'flex':'none'}`">
<div >请使用...扫码加入</div>
<div>...项目</div>
<div class="text">成为 ...</div>
<img v-if="qrcode" :src="qrcode" >
<div class="text text-base">该二维码7天(...)内有效</div>
</div>
<style>
.copy-content {
display: none;
position: relative;
z-index: -1;
......
}
</style>
2.使用dom-to-image转为blob数据。
<el-button@click="handleCopyImg">复制</el-button>
<a :href="blobToUrl(convertBase64ToBlob(qrcode.replace('data:image/png;base64,', ''), 'image/png'))" ref='qrcodeLink'>下载</a>
import domtoimage from 'dom-to-image';
handleCopyImg() {
if (navigator.clipboard) {
this.copyclick = true;
setTimeout(async () => {
try {
const node = document.getElementsByClassName('copy-content')[0];
// 方式一:这种方式也适合与base64格式的图片进行复制
// const res = await domtoimage.toPng(node);
// const blobInput = this.convertBase64ToBlob(res.replace('data:image/png;base64,', ''), 'image/png');
// 方式二:一步到位
const blobInput = await domtoimage.toBlob(node);
} catch (err) {
this.$message.error('复制二维码失败');
this.copyclick = false;
}
});
}
},
convertBase64ToBlob(base64, type) {
const bytes = window.atob(base64);
const ab = new ArrayBuffer(bytes.length);
const ia = new Uint8Array(ab);
for (let i = 0; i < bytes.length; i++) {
ia[i] = bytes.charCodeAt(i);
}
return new Blob([ab], { type });
},
blobToUrl(blobData) {
return URL.createObjectURL(blobData);
},
3.使用clipboard进行复制。
handleCopyImg() {
if (navigator.clipboard) {
this.copyclick = true;
setTimeout(async () => {
try {
const node = document.getElementsByClassName('copy-content')[0];
const blobInput = await domtoimage.toBlob(node);
const clipboardItemInput = new ClipboardItem({ 'image/png': blobInput });
await navigator.clipboard.write([clipboardItemInput]);
this.$message.success('复制二维码成功');
this.copyclick = false;
} catch (err) {
console.log('err');
this.$message.error('复制二维码失败');
this.copyclick = false;
}
});
} else {
this.$refs.qrcodeLink.click();
}
},
4.扩展小demo
贴两个其他博客中的小demo,省的想看的时候再找了。
1.图片的复制与粘贴demo
局限: 粘贴图片除了可以粘贴网页中的图片,也可以粘贴微信、QQ等软件中的截图,但直接从硬盘中复制的图片(本地图片)不可以 。
<!doctype html>
<html lang="zn">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
<title>复制图片</title>
<style>
.container {
display: flex;
}
.block {
margin-right: 30px;
}
img {
width: 300px;
height: 225px;
}
</style>
</head>
<body>
<div class="container">
<div class="block">
<button id="copyBtn">复制下图</button>
<div>
<img src="https://www.kkkk1000.com/images/clipboard/img/1.png" id="copyImg">
</div>
</div>
<div class="block">
<button id="pasteBtn">粘贴图片</button>
<div>
<img id="pasteImg">
</div>
</div>
</div>
<p>粘贴图片除了可以粘贴网页中的图片,也可以粘贴微信、QQ等软件中的截图,但直接从硬盘中复制的图片不可以。</p>
<script>
//复制图片
var copyBtn = document.querySelector('#copyBtn')
var copyImg = document.querySelector('#copyImg')
copyBtn.addEventListener('click', () => {
writeImg()
})
async function writeImg() {
const imgURL = copyImg.src
const data = await fetch(imgURL)
const blob = await data.blob()
await navigator.clipboard.write([
new ClipboardItem({
[blob.type]: blob
})
])
alert('已写入图片!')
}
//粘贴图片
var pasteBtn = document.querySelector('#pasteBtn')
var pasteImg = document.querySelector('#pasteImg')
pasteBtn.addEventListener('click', () => {
readImg()
})
function readImg() {
//获取权限
navigator.permissions.query({ name: 'clipboard-read' }).then(result => {
if (result.state == 'granted' || result.state == 'prompt') {
//读取剪贴板
navigator.clipboard.read()
.then(data => {
for (let i = 0; i < data.length; i++) {
if (!data[i].types.includes('image/png')) {
alert('请先复制图片!')
} else {
data[i].getType('image/png').then(blob => {
pasteImg.src = URL.createObjectURL(blob)
})
}
}
})
.catch(err => {
alert(err)
})
} else {
alert('请允许读取剪贴板!')
}
})
}
</script>
</body>
</html>
2.原生图片粘贴demo
<html>
<head>
<title>test chrome paste image</title>
<style>
#non-editable img{
width: 300px;
}
#editable {
margin-top: 20px;
width: 400px;
height: 300px;
border: 1px dashed blue;
}
#editable img{
width: 300px;
}
</style>
</head>
<body>
<h2>在浏览器中测试图像粘贴</h2>
<div id="non-editable">
<p>复制下面的img,然后粘贴到下面的区域</p>
<img
src="https://www.kkkk1000.com/images/clipboard/img/1.png" />
</div>
<div id="editable" contenteditable="true">
<p>这是一个可编辑的div区域</p>
<p>将图像粘贴到这里。</p>
</div>
</body>
</html>
<script type="text/javascript">
window.onload = function() {
function paste_img(e) {
if (e.clipboardData.items) {
// google-chrome
ele = e.clipboardData.items
for (var i = 0; i < ele.length; ++i) {
if (ele[i].kind == 'file' && ele[i].type.indexOf('image/') !== -1) {
var blob = ele[i].getAsFile();
window.URL = window.URL || window.webkitURL;
var blobUrl = window.URL.createObjectURL(blob);
var new_img = document.createElement('img');
new_img.setAttribute('src', blobUrl);
var new_img_intro = document.createElement('p');
new_img_intro.innerHTML =
'粘贴的img url: <br /><a target="_blank" href="' + blobUrl +
'">' + blobUrl + '</a>';
document.getElementById('editable').appendChild(new_img);
document.getElementById('editable').appendChild(new_img_intro);
}
}
} else {
alert('non-chrome');
}
}
document.getElementById('editable').onpaste = function() {
paste_img(event);
return false;
};
}
</script>