我正在尝试解决React应用程序的Windows用户无法复制和粘贴非Windows用户可以粘贴的内容的问题。
我们在反应模式窗口中显示内容,并带有一个按钮,当单击该按钮时,它会突出显示要复制的区域,然后复制到剪贴板缓冲区以进行粘贴。
我们正在通过按钮上的click事件触发的onCopy事件中运行以下内容:
const range = document.createRange();
range.selectNode(this.getCiteTextNode()); // function to get the node
window.getSelection().removeAllRanges();
window.getSelection().addRange(range);
const listener = document.addEventListener("copy", e => {
const outerHTML = this.getCitationTextWithoutStyle(); //function strips styling attributes
e.clipboardData.setData("text/html", outerHTML);
e.preventDefault();
});
document.execCommand("copy");
document.removeEventListener("copy", listener);
我观察到的是,尽管MacOS上的浏览器(Safari,Firefox,Chrome)允许进行此复制/粘贴操作,但在Windows,Edge,FF和Chrome中,它们会静默失败(剪贴板缓冲区中没有任何内容),即使已在这些浏览器中授予了程序访问权限。更重要的是,任何复制粘贴请求(菜单,鼠标或键盘)都无提示地失败;我可以手动突出显示模式的其他区域,选择复制,然后尝试粘贴到另一个文档中,但是它根本不会复制-没有东西可以将其复制到缓冲区中。
但是,确实在IE11中起作用-带有提示-但是在触发按钮单击事件时剪贴板访问行为正常。
进一步的实验表明,当我将preventDefault
更改为stopPropagation
时,这在Windows浏览器上有效。完成此操作后,内容将正确地放入剪贴板。
有人遇到过吗?如何防止事件冒泡如何在仅Windows浏览器中使此“工作”?
PS-了解execCommand的草稿状态。
谢谢
答案 0 :(得分:0)
序言 :此答案试图解释OP中的代码在做什么,他们可能会遇到什么以及如何处理。他们应该处理它,但是,Windows和macO对我而言实际上表现相同,这一事实使它有所削弱...
如果我们逐步执行您的代码,那就是
copy
命令copy
事件copy
事件outerHTML
设置为text/html
copy
事件的默认操作。如果没有阻止,则应该是“ 默认操作”
==>在剪贴板中将活动选择的标记抓取为text/HTML
。
=>在剪贴板中将所选内容的toString()
抓取为text/plain
。
也许您已经看到缺少的代码:
您未设置复制事件的text/plain
值。
只有少数应用程序会尝试从剪贴板中获取text/html
数据,大多数应用程序只会搜索text/plain
值。
所以您也需要设置它。
这里是一个小操场*,您可以在其中看到即使在网页中,也只有某些地方允许粘贴为text/html
,而其他地方将使用text/plain
值。
btn.onclick = e => {
const range = document.createRange();
range.selectNode(copyme); // function to get the node
const selection = getSelection();
selection.removeAllRanges();
selection.addRange(range);
const listener = e => {
// make it green in the clipboard
const outerHTML = copyme.outerHTML.replace('red', 'green');
// add some text to show we have the control
const plaintext = selection.toString() + ' plaintext';
const dT = e.clipboardData;
dT.setData("text/html", outerHTML);
// IIRC IE does only support `"text"` MIME type
dT.setData("text", plaintext);
e.preventDefault();
};
document.addEventListener("copy", listener);
document.execCommand("copy");
document.removeEventListener("copy", listener);
};
[contenteditable] {border: 1px solid;}
<button id="btn">copy</button>
<span id="copyme" style="color:red">Hello</span>
<br>
<!-- contenteditable elements will grab the text/html data -->
<div contenteditable>paste HTML here<br> </div>
<!-- <textarea> and <input> will only grab the text/plain -->
<textarea>paste plain here
</textarea>
*我从您的原始代码中修复了一些不相关的错别字,例如您的问题注释中指出的错误事件删除。
还要注意,并不是stopPropagation
在做任何魔术,而仅仅是您没有致电preventDefault
的事实。
这样做,将this.getCiteTextNode()
返回的Node的标记复制为text/html
并将其textContent复制为text/plain
的默认行为是覆盖您自己的设置。
这是一个带有复选框的示例,该复选框控制是否应阻止默认行为。您会看到,如果不阻止它,则复制的富文本仍然是 red ,而不是我们在事件处理程序中设置的绿色,而纯文本仍然是节点的textContent,编辑的文本中。
btn.onclick = e => {
const range = document.createRange();
range.selectNode(copyme); // function to get the node
const selection = getSelection();
selection.removeAllRanges();
selection.addRange(range);
const listener = e => {
// make it green in the clipboard
const outerHTML = copyme.outerHTML.replace('red', 'green');
// add some text to show we have the control
const plaintext = selection.toString() + ' plaintext';
const dT = e.clipboardData;
dT.setData("text/html", outerHTML);
// IIRC IE does only support `"text"` MIME type
dT.setData("text", plaintext);
if(prev.checked) {
e.preventDefault();
}
};
document.addEventListener("copy", listener);
document.execCommand("copy");
document.removeEventListener("copy", listener);
};
[contenteditable] {border: 1px solid;}
<label>prevent default behavior<input type="checkbox" id="prev" checked></label><br>
<button id="btn">copy</button>
<span id="copyme" style="color:red">Hello</span>
<br>
<!-- contenteditable elements will grab the text/html data -->
<div contenteditable>paste HTML here<br> </div>
<!-- <textarea> and <input> will only grab the text/plain -->
<textarea>paste plain here
</textarea>