使用 document.execCommand('copy') 复制到剪贴板(a la https://stackoverflow.com/a/30810322/3160967)适用于少量数据,如果您使用调试器单步执行,也适用,但失败当数据大小达到大约 150k 时(并且您没有使用调试器单步执行)。
此外,如果以 window.getSelection() 开头的代码异步运行,它似乎可以工作。为什么?异步解决方案是稳定的,还是只是掩盖而不解决问题?
使用 Chrome 版本 66.0.3359.139
要重现此问题,请打开 DevTools 并运行以下命令:
function doclick() {
copyTest();
}
document.addEventListener('click', doclick);
function copyTest() {
var data = [];
var n = 20000; // works if n is smaller e.g. < ~6000
for(var i = 0; i < n; i++)
data[i] = String(Math.random());
var textarea = document.createElement('textarea');
textarea.value = data.join('\t')
document.body.appendChild(textarea);
var sel = window.getSelection(); // works if debugger breaks here or earlier
sel.removeAllRanges();
var r = document.createRange();
r.selectNode(textarea);
sel.addRange(r);
document.execCommand('copy');
document.body.removeChild(textarea);
alert('copied ' + textarea.value.length);
}
在 DevTools 中运行它后,我点击页面运行 doCopy(),但剪贴板没有改变。但是,如果 n < 6000 左右,它会成功。此外,如果我在上面指示的行上设置一个断点,然后在它中断后继续运行代码,它将起作用。
此外,以下似乎有效:
function copyTest() {
var data = [];
var n = 20000; // works only if n is smaller e.g. < ~6000
for(var i = 0; i < n; i++)
data[i] = String(Math.random());
var textarea = document.createElement('textarea');
textarea.value = data.join('\t')
document.body.appendChild(textarea);
function copy() {
var sel = window.getSelection(); // works if debugger breaks here or earlier
sel.removeAllRanges();
var r = document.createRange();
r.selectNode(textarea);
sel.addRange(r);
document.execCommand('copy');
document.body.removeChild(textarea);
alert('copied ' + textarea.value.length);
}
window.setTimeout(copy); // this works
}
但是,我不确定为什么这应该起作用。看起来当window.getSelection在document.body.appendChild之后立即被调用时,当被追加的孩子有足够的数据量时,window.getSelection失败,可能是因为document.body.appendChild需要另一个异步循环才能完成?无论如何,这个问题的“正确”解决方案是什么——在纯 JS 中?