Преамбула : Этот ответ пытается объяснить, что делает код в OP, с чем они могут столкнулись, и как они должны обращатьсяэто, однако, немного ослаблено тем фактом, что и Windows, и macOs ведут себя для меня одинаково ...
Если мы пошагово сделаем ваш код, это будет
- Выберите узел в DOM.
- Выполните команду
copy
[внутренняя логика браузера]
=> Запустите copy
событие - Обработка события
copy
- Установка данных DataTransfer события.
=> Установить outerHTML
как text/html
в буфере обмена - Запретить действие по умолчанию
copy
event.
Если не предотвращено, то должно быть " действие по умолчанию ",
=> Получить разметку активного выделения как 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()
как text/html
, и его textContent как text/plain
переопределяет ваши собственные настройки.
Вот пример с флажком, управляющим тем, должно ли поведение по умолчанию бытьпредотвращено или нет.Вы можете видеть, что когда это не предотвращено, тогда копируемый форматированный текст по-прежнему красный вместо зеленого, который мы устанавливаем в обработчике событий, и простой текст по-прежнему является 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>