【问题标题】:Copy rich text to clipboard with styles from css-classes使用 CSS 类中的样式将富文本复制到剪贴板
【发布时间】:2019-03-31 10:35:22
【问题描述】:

我使用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

【问题讨论】:

    标签: javascript css dom clipboard


    【解决方案1】:

    添加到复制文本的换行是因为“块级元素”,即使您在 css 表中添加 "display : inline"

    W3 HTML Block and Inline Elements

    为避免这种情况,我们需要更改任何具有内联显示的块级元素并将所有样式包括默认样式恢复为新标签

    最后代码如下:

    Codepen

    注意:代码注释中的解释

    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>

    【讨论】:

    • 我没有 MS Word,但使用 LibreOffice,“Hello world”的内联格式被破坏了。 [1] [1]:i.stack.imgur.com/KyNHJ.jpg
    • @EugeneBarsky 答案已更新
    • 非常感谢您的帮助和分享您的知识!现在唯一的问题是复制到 LibreOffice 时的 div 元素保留了它们的边框:i.stack.imgur.com/V6wLD.jpg
    猜你喜欢
    • 2014-07-19
    • 1970-01-01
    • 2022-04-13
    • 1970-01-01
    • 2021-07-09
    • 1970-01-01
    • 2015-05-24
    • 1970-01-01
    • 2014-01-24
    相关资源
    最近更新 更多