Копировать в буфер обмена с помощью document.execCommand ('copy') (а-ля 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 или около того, он будет успешным. Кроме того, он будет работать, если я установлю точку останова на указанномна строчку выше, а затем продолжите выполнение кода после его разрыва. </p>
Более того, кажется, что ниже работает:
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?