使用 css-类 中的样式将富文本复制到剪贴板
Copy rich text to clipboard with styles from css-classes
我使用 this method 从 html 元素复制富文本。问题是,如果样式不是内联在 html 中,而是来自 css,则此方法不起作用。现有代码破坏了格式并且没有考虑样式。这是代码。
HTML
<button onclick="copyToClip(document.getElementById('foo').innerHTML)">
Copy the stuff
</button>
<div id=foo>
You can write some JS to generate this data.
It can contain rich stuff.
<b> test </b> me <i> also </i>
<div class="green">Hello world</div> You can use setData to put TWO COPIES into the same clipboard, one that is plain and one that is rich. That way your users can paste into either a
<ul>
<li>plain text editor</li>
<li>or into a rich text editor</li>
</ul>
</div>
CSS
.green {
display: inline;
color: green;
}
JavaScript
function copyToClip(str) {
function listener(e) {
e.clipboardData.setData("text/html", str);
e.clipboardData.setData("text/plain", str);
e.preventDefault();
}
document.addEventListener("copy", listener);
document.execCommand("copy");
document.removeEventListener("copy", listener);
};
范例in Codepen.
添加到复制文本的换行符是因为“块级元素”,即使您在 css sheet 中添加 "display : inline"
见W3 HTML Block and Inline Elements
为避免这种情况,我们需要更改任何具有内联显示的块级元素,并将所有样式(包括默认样式)恢复为新标签
最后代码会像这样:
注意 : 代码注释中的解释
function CopyToClipboard(element) {
// array off all block level elements
var block_level_elements = ['P','H1', 'H2', 'H3', 'H4', 'H5', 'H6','OL', 'UL','DIV','FORM','HR','TABLE'];
//create new Element so we can change elments like we need
var newelment = document.createElement("div");
//copy target Element to the new Element
newelment.innerHTML = document.getElementById(element).innerHTML;
//hide new Element to body
newelment.style.opacity = 0;
// add new Element to body
document.body.appendChild(newelment);
//get all element childs
var descendents = newelment.getElementsByTagName('*');
//loop in childs
for (var i = 0; i < descendents.length; ++i) {
//get defult Style
var style = window.getComputedStyle(descendents[i]);
var dis = style.getPropertyValue('display');
//get defult tag name
var tagname = descendents[i].tagName;
//---------------------------
//this part is little tricky
//---------------------------
//true : Element is a block level elements and css display is inline
if(dis.includes("inline") && block_level_elements.includes(tagname)){
//get all Element style include default style
var defultcss = document.defaultView.getComputedStyle(descendents[i], "").cssText;
//chang Element tag from block level elements to inline level elements (span)
descendents[i].outerHTML = descendents[i].outerHTML.replace(new RegExp(tagname, "ig"),"span"); //todo: need to change RegExp to tag name only not inner text
//add all Element style include default style to new tag
descendents[i].style.cssText = defultcss;
}
}
//-----------------copy new Element--------------
var doc = document;
var range, selection;
if (doc.body.createTextRange)
{
range = doc.body.createTextRange();
range.moveToElementText(newelment);
range.select();
}
else if (window.getSelection)
{
selection = window.getSelection();
range = doc.createRange();
range.selectNodeContents(newelment);
selection.removeAllRanges();
selection.addRange(range);
}
document.execCommand('copy');
window.getSelection().removeAllRanges();
// remove new Element from document
document.body.removeChild(newelment);
document.getElementById("copybtn").innerHTML="Copied";
}
.green {
display: inline;
color: green;
white-space: nowrap;
}
<button id='copybtn' onclick="CopyToClipboard('foo')">
Copy the stuff
</button>
<div id='foo'>
You can write some JS to generate this data.
It can contain rich stuff.
<b> test </b> me <i> also </i>
<div class="green" style="color: green;">Hello world</div> , <h3 class="green" style="color: green;">header3</h3> You can use setData to put TWO COPIES into the same clipboard, one that is plain and one that is rich. That way your users can paste into either a
<ul>
<li>plain text editor</li>
<li>or into a rich text editor</li>
</ul>
</div>
我使用 this method 从 html 元素复制富文本。问题是,如果样式不是内联在 html 中,而是来自 css,则此方法不起作用。现有代码破坏了格式并且没有考虑样式。这是代码。
HTML
<button onclick="copyToClip(document.getElementById('foo').innerHTML)">
Copy the stuff
</button>
<div id=foo>
You can write some JS to generate this data.
It can contain rich stuff.
<b> test </b> me <i> also </i>
<div class="green">Hello world</div> You can use setData to put TWO COPIES into the same clipboard, one that is plain and one that is rich. That way your users can paste into either a
<ul>
<li>plain text editor</li>
<li>or into a rich text editor</li>
</ul>
</div>
CSS
.green {
display: inline;
color: green;
}
JavaScript
function copyToClip(str) {
function listener(e) {
e.clipboardData.setData("text/html", str);
e.clipboardData.setData("text/plain", str);
e.preventDefault();
}
document.addEventListener("copy", listener);
document.execCommand("copy");
document.removeEventListener("copy", listener);
};
范例in Codepen.
添加到复制文本的换行符是因为“块级元素”,即使您在 css sheet 中添加 "display : inline"
见W3 HTML Block and Inline Elements
为避免这种情况,我们需要更改任何具有内联显示的块级元素,并将所有样式(包括默认样式)恢复为新标签
最后代码会像这样:
注意 : 代码注释中的解释
function CopyToClipboard(element) {
// array off all block level elements
var block_level_elements = ['P','H1', 'H2', 'H3', 'H4', 'H5', 'H6','OL', 'UL','DIV','FORM','HR','TABLE'];
//create new Element so we can change elments like we need
var newelment = document.createElement("div");
//copy target Element to the new Element
newelment.innerHTML = document.getElementById(element).innerHTML;
//hide new Element to body
newelment.style.opacity = 0;
// add new Element to body
document.body.appendChild(newelment);
//get all element childs
var descendents = newelment.getElementsByTagName('*');
//loop in childs
for (var i = 0; i < descendents.length; ++i) {
//get defult Style
var style = window.getComputedStyle(descendents[i]);
var dis = style.getPropertyValue('display');
//get defult tag name
var tagname = descendents[i].tagName;
//---------------------------
//this part is little tricky
//---------------------------
//true : Element is a block level elements and css display is inline
if(dis.includes("inline") && block_level_elements.includes(tagname)){
//get all Element style include default style
var defultcss = document.defaultView.getComputedStyle(descendents[i], "").cssText;
//chang Element tag from block level elements to inline level elements (span)
descendents[i].outerHTML = descendents[i].outerHTML.replace(new RegExp(tagname, "ig"),"span"); //todo: need to change RegExp to tag name only not inner text
//add all Element style include default style to new tag
descendents[i].style.cssText = defultcss;
}
}
//-----------------copy new Element--------------
var doc = document;
var range, selection;
if (doc.body.createTextRange)
{
range = doc.body.createTextRange();
range.moveToElementText(newelment);
range.select();
}
else if (window.getSelection)
{
selection = window.getSelection();
range = doc.createRange();
range.selectNodeContents(newelment);
selection.removeAllRanges();
selection.addRange(range);
}
document.execCommand('copy');
window.getSelection().removeAllRanges();
// remove new Element from document
document.body.removeChild(newelment);
document.getElementById("copybtn").innerHTML="Copied";
}
.green {
display: inline;
color: green;
white-space: nowrap;
}
<button id='copybtn' onclick="CopyToClipboard('foo')">
Copy the stuff
</button>
<div id='foo'>
You can write some JS to generate this data.
It can contain rich stuff.
<b> test </b> me <i> also </i>
<div class="green" style="color: green;">Hello world</div> , <h3 class="green" style="color: green;">header3</h3> You can use setData to put TWO COPIES into the same clipboard, one that is plain and one that is rich. That way your users can paste into either a
<ul>
<li>plain text editor</li>
<li>or into a rich text editor</li>
</ul>
</div>