Как скопировать форматированный текст в буфер обмена в ReactJS? - PullRequest
0 голосов
/ 25 марта 2020

Мне нужно скопировать элемент JSX в буфер обмена, когда я нажимаю кнопку. У этого конкретного JSX есть различные цвета и стиль, ничего особенного. Фактически, это очень похоже на единственное рабочее решение, которое я нашел в inte rnet: https://codepen.io/theXstar/pen/EJxWNo.

Когда я запускаю в codepen, код работает отлично. В моей тестовой среде это не так. Я не знаю, связано ли это с нативным JavaScript, не работающим в React App или чем-то еще. Ну, я так и думал, потому что это JavaScript, верно?

Вот что я пытался:

import React from 'react';
import { Button } from 'antd';
//import ReactHtmlParser, { processNodes, convertNodeToElement, htmlparser2 } from 'react-html-parser';

const foof = (
    <div className='toBeCopied'>
        You can write some JS to generate this data. 
        It can contain rich stuff.
        <b> test </b> me <i> also </i>
        <div className="green" style={{color: 'green'}}>Hello world</div> , <h3 className="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>
)

class CopyTest extends React.Component {

    enterLoading = () => {
        CopyToClipboard(foof);
    };

    render () {
        return (
            <div>
                <Button type="primary" onClick={this.enterLoading}>
                        Copy To Clipboard
                </Button>

                <div>{ foof }</div>;
            </div>
        )
    }
}

export default CopyTest;

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 vhange 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('*');

    console.log(element)
    console.log(descendents)

    //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;

    console.log(doc.body.createTextRange, window.getSelection)
    console.log(document)
    console.log("document.body", document.body)
    console.log("newElem", newelment)

    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);  
}

В файле console.log есть, потому что я пытался понять, где это может идти не так, но, похоже, возвращает значения нормально. Единственное, что вернуло undefined , это do c .body.createTextRange , но я думаю, что это связано с браузером, который я использую (Chrome).

Код работает нормально. Нет ошибок, ничего. Но это ничего не копирует в буфер обмена. Что я делаю не так?

...