[英]Cannot set data to clipboard after getting data from web worker
当触发复制事件(cmd + c)时,我们的应用程序需要从 web worker 调用并获取数据,然后将其设置到剪贴板。
但是数据准备好后,将数据设置到剪贴板似乎不起作用。
async function process_copy(event) {
let data = await get_data_from_worker();
console.log("DATA FROM WORKER: ", data);
event.clipboardData.setData('text/plain', data);
event.clipboardData.setData('text/html', data);
event.preventDefault();
}
window.addEventListener('copy', process_copy.bind(this));
我需要将数据设置到剪贴板,因为来自 web 工作人员的数据可供使用。
我无法使用此命令的原因
document.execCommand('copy')
因为从 web worker 获取数据的时间可能会超过 5 秒,而上面的命令在这些情况下不起作用。
这是一个例子:
worker.js
onmessage = function(e) {
postMessage('WORKER DATA');
}
索引.html
<!DOCTYPE html>
<html>
<body>
<script>
window.onload = function() {
const my_worker = new Worker("worker.js");
let call_back;
my_worker.onmessage = function(e) {
if(call_back){
call_back(e.data);
}
call_back = undefined;
}
function get_data_from_worker() {
return new Promise(
function(resolve, reject) {
call_back = resolve;
my_worker.postMessage("GET DATA");
}
)
}
async function process_copy(event) {
let data = await get_data_from_worker();
console.log("DATA FROM WORKER: ", data);
event.clipboardData.setData('text/plain', data);
event.clipboardData.setData('text/html', data);
event.preventDefault();
}
window.addEventListener('copy', process_copy.bind(this));
};
</script>
</body>
</html>
用户触发复制事件后,调用process_copy function,等待数据。
在get_data_from_worker function 中,我创建了一个 promise,它将消息发送到 web worker,然后将解析存储在call_back中以供以后使用。
当 web worker 收到消息时,它会准备数据并通过postMessage方法发回。
然后, web worker 消息将由call_back (在my_worker.onmessage内部)返回。
之后, process_copy function 中的数据就准备好了。 但是我们不能将该数据设置到剪贴板。
您正确识别了问题:您需要同步处理事件才能覆盖其默认行为。
您可以通过重新设计工作流程来解决该问题。
如果您的数据确实需要 5 秒才能生成,那么您很可能需要用户点击两次:
您无需实际处理他们的复制事件即可在其中设置数据,因此单击即可,但是,需要单击,因为浏览器不允许我们在没有用户手势的情况下复制剪贴板中的任何内容,并且5 秒后,大多数浏览器会认为用户手势已经失效。
btn.onclick = async (evt) => { // from first click we prepare the data btn.disabled = true; btn.textContent = "Please wait"; // simulate waiting for worker await wait(1000); const datatext = "data as text"; const datahtml = "<h1>data as html</h1>"; // now that the data is ready // we wait for the second click btn.disabled = false; btn.textContent = "Copy to clipboard"; btn.onclick = async (evt) => { // we prepare to handle the click event // so we can overwrite its content addEventListener("copy", evt => { evt.preventDefault(); evt.clipboardData.setData("text/plain", datatext); evt.clipboardData.setData("text/html", datahtml); }, { once: true }); // we force the copy event (we don't care of the content here) document.execCommand("copy"); btn.remove(); pastezone.classList.remove("hidden"); }; }; pastezone.addEventListener("paste", (evt) => { console.log("as text:", evt.clipboardData.getData("text/plain")); console.log("as html:", evt.clipboardData.getData("text/html")); }); function wait(ms) { return new Promise( (res) => setTimeout(res, ms) ); }
.hidden { display: none; }
<button id="btn">Prepare data to copy</button> <textarea id="pastezone">You can paste here to test </textarea>
如果您只需要编写文本并且需要支持 IE,您还可以使用异步剪贴板 API代替document.execCommand
,但这在 StackOverflow 的沙盒代码片段中不起作用。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.