|
|
|
|
@ -31,6 +31,11 @@
|
|
|
|
|
@click="changeImage('next')"
|
|
|
|
|
><ArrowRightBold
|
|
|
|
|
/></el-icon>
|
|
|
|
|
<!-- 自定义右键菜单 -->
|
|
|
|
|
<ul id="customContextMenu">
|
|
|
|
|
<li @click="saveCanvasAsImage">图片下载</li>
|
|
|
|
|
<li @click="copyCanvasToClipboard">复制图片</li>
|
|
|
|
|
</ul>
|
|
|
|
|
</div>
|
|
|
|
|
</Teleport>
|
|
|
|
|
</template>
|
|
|
|
|
@ -251,6 +256,62 @@ const initTuiImageEditor = () => {
|
|
|
|
|
|
|
|
|
|
// 针对图片加载首次不显示,必须手动调用一次refreshImageShow方法(个人项目未复现,公司项目有该问题,考虑是返回的图片的加载方式问题或者格式等问题)
|
|
|
|
|
// refreshImageShowWithDelay(300, true);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* canvas禁用右键功能
|
|
|
|
|
* 该组件默认有两层canvas,第一层图片canvas在底部,画布canvas在顶部,需要禁用右键功能(如果不禁用,会导致默认右键复制和保存的图片是画布这一层,空白的图片)
|
|
|
|
|
* 再自定义右键功能,实现图片下载和复制到剪贴板功能
|
|
|
|
|
*/
|
|
|
|
|
const canvas = document.querySelector('.upper-canvas');
|
|
|
|
|
const customContextMenu = document.querySelector('#customContextMenu');
|
|
|
|
|
canvas.addEventListener('contextmenu', (e) => {
|
|
|
|
|
console.log(customContextMenu);
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
|
|
|
|
|
// 显示自定义菜单
|
|
|
|
|
customContextMenu.style.display = 'block';
|
|
|
|
|
customContextMenu.style.left = e.pageX + 'px';
|
|
|
|
|
customContextMenu.style.top = e.pageY + 'px';
|
|
|
|
|
});
|
|
|
|
|
// 点击其他地方隐藏菜单
|
|
|
|
|
document.querySelector('.tui-image-editor-wrap').addEventListener('click', () => {
|
|
|
|
|
customContextMenu.style.display = 'none';
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const saveCanvasAsImage = () => {
|
|
|
|
|
const canvas = document.querySelector('.lower-canvas');
|
|
|
|
|
const a = document.createElement('a');
|
|
|
|
|
a.href = canvas.toDataURL('image/jpeg');
|
|
|
|
|
a.download = new Date().getTime() + '.jpg';
|
|
|
|
|
a.click();
|
|
|
|
|
a.remove();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 复制图片到剪贴板功能如果是以iframe嵌入,必须要在嵌入加上<iframe allow="clipboard-write"></iframe>属性才可以正常使用
|
|
|
|
|
const copyCanvasToClipboard = async () => {
|
|
|
|
|
const canvas = document.querySelector('.lower-canvas');
|
|
|
|
|
/**
|
|
|
|
|
问题的现象
|
|
|
|
|
在使用浏览器的剪贴板API的 write 方法尝试将JPEG图像写入剪贴板时,我们可能会遇到这样的错误:DOMException: Failed to execute 'write' on 'Clipboard': Type image/jpeg not supported on write.
|
|
|
|
|
问题的原因
|
|
|
|
|
这个错误的产生主要是因为 write 方法目前只支持 text/plain 和 text/html MIME 类型,这意味着你不能直接将JPEG图像写入剪贴板。然而,为什么浏览器的剪贴板API会有这样的限制呢?
|
|
|
|
|
在深入浏览器的内部实现之前,我们先来了解一下剪贴板API。剪贴板API是浏览器提供的一种接口,用于访问用户的剪贴板。它的主要目的是为了提供一种简单、一致的方式来读取和写入剪贴板数据。
|
|
|
|
|
然而,由于安全和隐私的考虑,浏览器的剪贴板API并不允许直接访问剪贴板中的所有类型的数据。例如,它不允许访问剪贴板中的图像数据,除非用户明确地进行了粘贴操作。这就是为什么我们不能直接将JPEG图像写入剪贴板的原因。
|
|
|
|
|
解决方案
|
|
|
|
|
那么,我们应该如何解决这个问题呢?一种可能的解决方案是将JPEG图像转换为PNG图像,然后将其写入剪贴板。这个方法可能不适用于所有浏览器,因为不是所有浏览器都支持 clipboard.write 方法或 ClipboardItem 对象。但是,我将提供的代码已经在大多数现代浏览器中进行了测试,并且可以正常工作。
|
|
|
|
|
*/
|
|
|
|
|
// 这里图片格式只能使用png,原因如上
|
|
|
|
|
const blob = await new Promise((resolve) => {
|
|
|
|
|
canvas.toBlob(resolve, 'image/png');
|
|
|
|
|
});
|
|
|
|
|
if (navigator.clipboard && navigator.clipboard.write) {
|
|
|
|
|
await navigator.clipboard.write([
|
|
|
|
|
new ClipboardItem({
|
|
|
|
|
'image/png': blob,
|
|
|
|
|
}),
|
|
|
|
|
]);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const addEventListenerFN = () => {
|
|
|
|
|
@ -266,7 +327,8 @@ const handleClickOutside = (event) => {
|
|
|
|
|
if (
|
|
|
|
|
getBtnDom('.save-btn').contains(event.target) ||
|
|
|
|
|
getBtnDom('.left-btn').contains(event.target) ||
|
|
|
|
|
getBtnDom('.right-btn').contains(event.target)
|
|
|
|
|
getBtnDom('.right-btn').contains(event.target) ||
|
|
|
|
|
getBtnDom('#customContextMenu').contains(event.target)
|
|
|
|
|
) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
@ -472,4 +534,27 @@ body > svg:last-of-type {
|
|
|
|
|
.tui-image-editor-container div.tui-colorpicker-clearfix {
|
|
|
|
|
display: none !important;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#customContextMenu {
|
|
|
|
|
position: absolute;
|
|
|
|
|
display: none;
|
|
|
|
|
background-color: #fff;
|
|
|
|
|
padding: 10px 0;
|
|
|
|
|
border-radius: 5px;
|
|
|
|
|
|
|
|
|
|
li {
|
|
|
|
|
box-sizing: border-box;
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
color: #666;
|
|
|
|
|
width: 100%;
|
|
|
|
|
height: 30px;
|
|
|
|
|
line-height: 30px;
|
|
|
|
|
padding: 0 10px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
li:hover {
|
|
|
|
|
background-color: #f5f5f5;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
</style>
|
|
|
|
|
|