将没有丰富样式的纯文本复制到剪贴板而不会失去焦点?

Hri*_*dov 6 html javascript clipboard focus selection

我查看了这个问题,其中要求提供一种简单地将文本复制为纯文本的方法。我想做到这一点,但还有一件事 - 不要失去对当前元素的关注。

我需要这个作为 Chrome 扩展程序,所以我不介意跨浏览器支持。当用户输入输入(或contenteditable)时,会出现一个带有选项的下拉列表。如果他选择其中之一,它将被复制到他的剪贴板。我不希望元素失去焦点,因为某些站点可能已经实现了在元素blur事件上运行的逻辑。

这是我尝试过的:

解决方案1

创建一个<input>元素并使用它的select()方法:

function clipWithInput(text) {
    var input = document.createElement("input");
    document.body.appendChild(input);

    input.addEventListener("focus", function (e) {
        e.preventDefault();
        e.stopPropagation();
    });

    input.value = text;
    input.select();

    document.execCommand("copy");
    document.body.removeChild(input);
}

document.getElementById("choice").onmousedown = function (e) {
  e.preventDefault(); // prevents loss of focus when clicked
  clipWithInput("Hello");
};
Run Code Online (Sandbox Code Playgroud)
#main {background: #eee;}
#choice {background: #fac;}
Run Code Online (Sandbox Code Playgroud)
<div id="main" contenteditable="true">Focus this, click the div below and then paste here.</div>
<div id="choice">Click to add "Hello" to clipboard</div>
Run Code Online (Sandbox Code Playgroud)

如您所见,这是有效的。文本被复制。但是,当您聚焦contenteditable并单击“选择”时,焦点就会丢失。选择元素preventDefault()在其mousedown事件上有导致它不会中断焦点。虚拟<input>元素是这里的问题,即使它有preventDefault()它的focus事件。我想这里的问题是为时已晚 - 初始元素已经触发了它的blur,所以我的虚拟输入focus是无关紧要的。

解决方案2

使用虚拟文本节点和选择 API:

function clipWithSelection(text) {
    var node = document.createTextNode(text),
        selection = window.getSelection(),
        range = document.createRange(),
        clone = null;

    if (selection.rangeCount > 0) {
        clone = selection.getRangeAt(selection.rangeCount - 1).cloneRange();
    }

    document.body.appendChild(node);
    selection.removeAllRanges();
    range.selectNodeContents(node);
    selection.addRange(range);
    document.execCommand("copy");

    selection.removeAllRanges();
    document.body.removeChild(node);

    if (clone !== null) {
        selection.addRange(clone);
    }
}

document.getElementById("choice").onmousedown = function (e) {
  e.preventDefault(); // prevents loss of focus when clicked
  clipWithSelection("Hello");
};
Run Code Online (Sandbox Code Playgroud)
#main {background: #eee;}
#choice {background: #fac;}
Run Code Online (Sandbox Code Playgroud)
<div id="main" contenteditable="true">Focus this, click the div below and then paste here.</div>
<div id="choice">Click to add "Hello" to clipboard</div>
Run Code Online (Sandbox Code Playgroud)

乍一看,这非常有效。文本被复制,没有焦点丢失,插入符号保持在同一位置。没有戏剧性。但是,当您将文本粘贴到contenteditable(如 Gmail 的电子邮件编辑器)中时,结果如下:

<span style="color: rgb(0, 0, 0); font-family: "Times New Roman"; font-size: medium;">Hello</span>
Run Code Online (Sandbox Code Playgroud)

不是纯文本。

  • 我尝试将元素附加到 <head>没有样式地方- 不。未选择文本且未复制任何内容。
  • 我试图追加文本节点的<span>并集类的东西style.fontFamily来inherit,还有fontSize和color。还是不行。我记录了虚拟元素,它正确地具有我的inherit样式。但是,粘贴的文本没有。

回顾

我想以编程方式复制没有样式的纯文本,同时保留对当前活动元素的关注。

Bea*_*ist 0

你的解决方案(尤其是2)没问题。当您粘贴到 中时contenteditable,需要预料到会插入跨度代码,许多人在 中使用它insertHTML。您不应期望以编程方式实现纯文本。有些人建议contenteditable根本不使用 a (尽管我知道您正在谈论某些扩展)。但你的解决方案比 MDN 等更兼容移动设备。

因此,您可以以编程方式复制纯文本,不添加任何样式(如果没有contenteditable),同时保留对当前元素的关注。