简体   繁体   English

在Javascript中以编程方式复制和选择范围(使用clipboard.js)

[英]copying & selecting a span programmatically in Javascript (with clipboard.js)

Context 上下文

The real free software (GPLv3) application (motivating this question) that I am coding is the MELT monitor on github (FWIW, I am at commit 56a83d358d3966eddb55... on February 11 th , 2016). 我正在编码的真正的自由软件(GPLv3)应用程序(激发这个问题)是github上的MELT监视器 (FWIW,我在2016年2月11 日的提交56a83d358d3966eddb55 ... )。 It is on Linux/x86_64/Debian, Firefox/44, JQuery-2.2.0, JqueryUI 1.11.4, clipboard.js 1.5.8.... 它在Linux / x86_64 / Debian,Firefox / 44,JQuery-2.2.0,JqueryUI 1.11.4,clipboard.js 1.5.8 ....

A more open (but without code) related question was downvoted on Programmers. 一个更开放(但没有代码)的相关问题被低估了程序员。 So I made a JsFiddle example for this very question, but that JsFiddle example is probably very wrong. 所以我为这个问题做了一个JsFiddle示例 ,但是JsFiddle示例可能非常错误。

I have a (dynamically generated) HTML document with some <span> -s of class='momitemref_cl' like <span class='momitemref_cl'>this</span> etc... (the inside content of such spans is always a single word like this , actually some variable name or identifier in some DSL of mine). 我有一个(动态生成的)HTML文档,其中一些<span> -s of class='momitemref_cl'<span class='momitemref_cl'>this</span>等......(此类跨度的内部内容始终是像this单词,实际上是某些DSL中的变量名称或标识符)。 My goal is to have a dynamically generated menu for each such spans to enable some operations on them, in particular: hilight every occurrence of that word, and copy & select the word to the browser's and desktop's clipboard. 我的目标是为每个这样的跨度创建一个动态生成的菜单 ,以便对它们进行一些操作 ,特别是:每次出现该单词时都会出现hilight ,然后将该单词复制并选择到浏览器和桌面的剪贴板。

There are many questions here about copying to the clipboard in Javascript , such as this one. 这里有很多关于在Javascript中复制到剪贴板的问题,例如这个问题。 Several of them mention Zeno Rocha's clipboard.js which I am trying to use. 其中有几个提到我试图使用的Zeno Rocha的clipboard.js

Code with explanation 代码说明

To explain some of the JsFiddle: I am creating the JQueryUI menu with 解释一些JsFiddle:我正在创建JQueryUI 菜单

// make a menu for the given span
function make_menu(spa) {
  console.log("make_menu spa=", spa);
  var name = $(spa).text();
  mom_menuitemcount++;
  var menuid = "menuid_" + mom_menuitemcount;
  console.log("make_menu name=", name, " menuid=", menuid);
  $maindiv.after("<ul class='mommenu_cl' id='" + menuid + "'>"
               + "<li class='ui-state-disabled'>* <i>" + name + "</i> *</li>"
    // the text inside the following <li> matters
    + "<li>Hilight</li>" + "<li>Copy</li>" + "</ul>");
  var mymenu = $('#' + menuid);
  mymenu.menu({
    select: function(ev, ui) {
      var uitem = ui.item;
      var utext = uitem.text();
      console.log("mymenu-select ev=", ev, " ui=", ui, " name=", name,
        " uitem=", uitem, " utext=", utext);
      switch (utext) {
        case "Hilight":
          $maindiv.find(".momitemref_cl").each(function(ix, el) {
            var etext = $(el).text();
            console.log("hilighting el=", el, " etext=", etext);
            if (etext == name) {
              $(el).toggleClass("momhilight_cl");
            }
          });
          break;
        case "Copy":
          //// what should go here?
          break;
      };
      setTimeout(200, destroy_menu);
    },
    position: {
      my: "left top",
      at: "bottom left",
      of: spa
    }
  });
  mom_menuitem = mymenu;
  console.log("make_menu spa=", spa, " mymenu=", mymenu);
  return mymenu;
}

In the above code, I don't know what to put in //// what should go here? 在上面的代码中,我不知道该放//// what should go here? ; ; perhaps it might be something similar to: 也许它可能类似于:

uitem.select();
document.execCommand('Copy');

but AFAIU this don't work as expected, and I feel that clipboard operations need the user event (eg a mouse click or down) trigerring them. 但AFAIU这不能按预期工作,我觉得剪贴板操作需要用户事件(例如鼠标点击或向下)来触发它们。

The clipboard is initialized with 剪贴板初始化为

$clipboardh = new Clipboard(".momitemref_cl", {
  text: function (trig) {
    console.log("clipboard text trig=", trig);
    /// some code is missing here probably
  };
});

I guess (but I am not sure) that the /// some code is missing here probably should return the text value of the relevant span. 我想(但我不确定) /// some code is missing here probably应该返回相关跨度的文本值。

Questions 问题

So I don't know how to copy the span's content to the clipboard ( //// what should go here? ....) and how to put into the clipboard its text ( /// some code is missing here probably ....) 所以我不知道如何将span的内容复制到剪贴板( //// what should go here? ....)以及如何将其文本放入剪贴板( /// some code is missing here probably 。 ...)

The full MVCE code is this JsFiddle 完整的MVCE代码就是这个JsFiddle

In other words, how to use clipboard.js from a JQueryUI menu item to copy a span 's content to the browser's clipboard ?? 换句话说, 如何使用JQueryUI菜单项中的clipboard.jsspan的内容复制到浏览器的剪贴板?


Perhaps the entire approach is wrong, and perhaps I should use contextmenu (but then, how to customize it only for span -s of class='momitemref_cl' ?) 也许整个方法都是错误的,也许我应该使用contextmenu (但是,如何仅针对class='momitemref_cl' span -s来定制它?)

To make things even more complex, I actually have in MELT monitor (but not in this JsFiddle ...) two CSS classes mom_itemref_cl & mom_itemval_cl that I want to behave likewise. 为了使事情变得更复杂,我实际上已经在MELT监视器中 (但不是在这个JsFiddle中 )两个CSS类mom_itemref_clmom_itemval_cl ,我想表现得同样如此。


PS. PS。 I messed the JsFiddle when copying code here. 我在这里复制代码时搞砸了JsFiddle。 I updated it, https://jsfiddle.net/bstarynk/g2notLd7/132/ 我更新了它, https://jsfiddle.net/bstarynk/g2notLd7/132/

NB. NB。 I could be satisfied with an answer working only on recent Firefox & Chrome. 我对仅在最近的Firefox和Chrome上工作的答案感到满意。

Clipboard.js needs to be attached to the element that triggers the copy event. 需要将Clipboard.js附加到触发复制事件的元素。 In your case, this is the <li>Copy</li> element inside the mommenu_cl menu, which you create dynamically when a momitemref_cl is right clicked. 在您的情况下,这是mommenu_cl菜单中的<li>Copy</li>元素,您可以在右键单击momitemref_cl时动态创建该momitemref_cl You can attach clipboard.js to the Copy li dynamically when you create the menu itself. 创建菜单本身时,可以动态地将clipboard.js附加到Copy li You will also have to destroy the clipboard when you destroy the menu. 在销毁菜单时,您还必须销毁剪贴板。

First, let's fix the typo in your updated fiddle, on line 87: 首先,让我们在第87行修正你更新的小提琴中的拼写错误:

curmenu[0].stle.left = Math.round(ev.pageY) + 5;

Then, remove the clipboard from your DOM's ready handler, we'll move this to the make_menu function: 然后,从DOM的就绪处理程序中删除剪贴板,我们将其移至make_menu函数:

$(document).ready(function() {
  $maindiv = $('#maindiv_id');
  // no clipboard initialization here
  console.log("our document ready function");
  ...
});

Next, at the top of your script, were you first declare $clipboardh , initialize it to false . 接下来,在脚本的顶部,您首先声明$clipboardh ,将其初始化为false Later, you will be checking to make sure you only attach the clipboard in case it is not currently attached. 稍后,您将检查以确保您只附加剪贴板,以防它当前未连接。

/// javascript code
var $clipboardh = false;

In your make_menu function, give your <li>Copy</li> element a class="copy" attribute so you can easily attach clipboard.js to it, and a data-clipboard-text attribute set to the value you want clipboard.js to copy when the element is clicked. make_menu函数中,为<li>Copy</li>元素提供class="copy"属性,以便您可以轻松地将clipboard.js附加到它,并将data-clipboard-text属性设置为您想要剪贴板的值。单击元素时要复制的js。

Because the name variable contains the text value you want to copy, your menu will look something like: 由于name变量包含要复制的文本值,因此菜单将如下所示:

$maindiv.after("<ul class='mommenu_cl' id='" + menuid + "'>" +
        "<li class='copy' data-clipboard-text='" + name + "'>Copy</li>" + 
    "</ul>");

Next, just after this code in your make_menu function, attach clipboard.js, only if it was not already attached: 接下来,在make_menu函数中的此代码之后,附加clipboard.js,仅当它尚未附加时:

if ($clipboardh === false){
  console.log("creating the clipboard");
  $clipboardh = new Clipboard('.copy');

  // some optional event handlers for debugging
  $clipboardh.on('success', function(e) {
      console.info('Action:', e.action);
      console.info('Text:', e.text);
      console.info('Trigger:', e.trigger);

      e.clearSelection();
  });

  $clipboardh.on('error', function(e) {
      console.error('Action:', e.action);
      console.error('Trigger:', e.trigger);
  });
}

Finally, you will want to make sure you destroy the clipboard when you destroy the menu, by adding this to the bottom of your destroy_menu function: 最后,您需要确保在销毁菜单时销毁剪贴板,方法是将其添加到destroy_menu函数的底部:

$clipboardh.destroy();
$clipboardh = false;

You can find a working fiddle here. 你可以在这里找到一个工作小提琴。

Copying from the clipboard from anything other than IE needs to happen on an editable element. 从IE以外的任何其他内容复制需要在可编辑元素上进行。 The most common way to handle this is to create a hidden textarea, put the content in the text area and then 处理此问题的最常用方法是创建隐藏的文本区域,然后将内容放入文本区域

textArea.select();
document.execCommand('Copy');

For IE, you can just use 对于IE,你可以使用

if(window.clipboardData){
    window.clipboardData.setData('Text',
        uitem.innerText);
}

I wrote a pretty extensive article explaining how this all works and I have a project on GitHub with the resulting code. 我写了一篇非常广泛的文章,解释了这一切是如何工作的,我在GitHub上有一个带有结果代码的项目。

http://blog.dmbcllc.com/cross-browser-javascript-copy-and-paste/ http://blog.dmbcllc.com/cross-browser-javascript-copy-and-paste/

It took me months to sort out all of the conflicting advice available by searching Google because HOW you do this keeps changes as the browsers "mature". 我花了几个月的时间来通过搜索Google来解决所有可用的冲突建议,因为你这样做会随着浏览器“成熟”而不断变化。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM