Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/465.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在javascript中将大量html内容复制到剪贴板而不超时_Javascript_Clipboard - Fatal编程技术网

如何在javascript中将大量html内容复制到剪贴板而不超时

如何在javascript中将大量html内容复制到剪贴板而不超时,javascript,clipboard,Javascript,Clipboard,我注意到document.execCommand('copy')命令在后台运行大约5秒后超时。有没有办法绕过这一限制,或者如果需要更长的时间,是否有退路 这是我一直在使用的页面。例如,我有一个函数“准备”数据(从表格数据生成html),然后有第二个函数将数据复制到剪贴板,并附加一些标记。在大型表上,从用户按下Cmd-C到生成并能够复制html,这通常需要大约10秒钟的时间 此外,我注意到Google Sheets允许复制超过5秒的操作,所以我很好奇他们会怎么做: # still works af

我注意到
document.execCommand('copy')
命令在后台运行大约5秒后超时。有没有办法绕过这一限制,或者如果需要更长的时间,是否有退路

这是我一直在使用的页面。例如,我有一个函数“准备”数据(从表格数据生成html),然后有第二个函数将数据复制到剪贴板,并附加一些标记。在大型表上,从用户按下Cmd-C到生成并能够复制html,这通常需要大约10秒钟的时间

此外,我注意到Google Sheets允许复制超过5秒的操作,所以我很好奇他们会怎么做:

# still works after 25 seconds!
[Violation] 'copy' handler took 25257ms     2217559571-waffle_js_prod_core.js:337 
代码被缩小/模糊,因此很难读取,但下面是上面的文件:

作为参考,复制的数据量约为50MB。请在复制操作上使用约10秒的延迟来模拟此长时间运行的过程


对于赏金,我希望有人能展示一个使用单个Cmd-C的工作示例:

  • 是否可以在后台(即异步)进行长时间运行的复制操作,例如使用web worker
  • 如果必须同步执行,例如执行复制操作,显示一些进度——例如,复制操作可能在大约每10k行之后发出一个事件
它必须生成html,并且必须只涉及一个Cmd-C(即使我们使用
preventDefault
并在后台触发复制事件)


您可以将以下内容用作“html生成”功能应如何工作的模板:

function sleepFor( sleepDuration ){
    var now = new Date().getTime();
    while(new Date().getTime() < now + sleepDuration){ /* do nothing */ } 
}

// note: the data should be copied to a dom element and not a string
//       so it can be used on `document.execCommand("copy")`
//       but using a string below as its easier to demonstrate
//       note, however, that it will give a "range exceeded" error
//       on very large strings  (when using the string, but ignore that, 
//       as it won't occur when using the proper dom element

var sall='<html><table>'
var srow='<tr><td  ><div style="text-align: right"><span style="color: #060606; ">1</span></div></td><td  ><div style="text-align: right"><span style="color: #060606; ">Feb 27, 2018</span></div></td><td  ><div style="text-align: right"><span style="color: #060606; ">315965</span></div></td><td  ><div style="text-align: left"><span style="color: #060606; ">CA</span></div></td><td  ><div style="text-align: left"><span style="color: #060606; ">SDBUY</span></div></td><td  ><div style="text-align: right"><span style="color: #060606; ">9.99</span></div></td><td  ><div style="text-align: left"><span style="color: #060606; ">CAD</span></div></td><td  ><div style="text-align: right"><span style="color: #060606; ">7.88</span></div></td></tr>'
for (i=0; i<1e6; i++) {
    sall += srow;
    if (i%1e5==0) sleepFor(1000); // simulate a 10 second operation...
    if (i==(1e6-1)) console.log('Done')
}
sall += '</table></html>'
// now copy to clipboard
函数sleepFor(睡眠持续时间){
var now=new Date().getTime();
while(new Date().getTime()
函数更新主板(newClip){
navigator.clipboard.writeText(newClip).then(function(){
/*剪贴板已成功设置*/
},函数(){
//超时函数处理程序
/*剪贴板写入失败*/
});
}

老实说,我没有看到相同的行为。(编辑:我会注意到我们使用的是略有不同的复制命令)当我照原样使用HTML生成函数时,我得到了一个内存限制错误。具体来说,在循环中附加行的行处出现“Uncaught RangeError:Invalid string length”

如果我降低你的循环(到
I{
函数sleepFor(sleepDuration){
var now=new Date().getTime();
while(new Date().getTime()
我怀疑这是否能解决您的实际问题,但这太多了,无法在评论中输入。不过,我希望无论是什么原因导致我们看到的行为差异都会有所帮助。

根据浏览器的不同,这可能不起作用。在Firefox上,它将不起作用,您将在控制台中看到如下消息:

document.execCommand('cut'/'copy')被拒绝,因为它不是从短时间运行的用户生成的事件处理程序内部调用的。

要启用此用例,您需要请求“clipboardWrite”权限。因此,“clipboardWrite”允许您在用户操作的短期事件处理程序之外写入剪贴板

因此,您的数据准备可能需要多长时间,但对
execCommand('copy')
的调用必须在用户生成事件(其处理程序正在运行该事件)后立即执行。 显然,它可能是任何事件处理程序,而不仅仅是复制事件

  • copyFormatted
    执行复制

  • genHtml
    函数同步生成HTML数据

  • enableCopy
    将在允许复制的上下文中创建的函数分配给
    delegateCopy
    ,该函数在一秒钟后过期(将null分配给
    delegateCopy

  • 有人提到了使用
    clipboardData
    的可能性,虽然这个界面更具编程性,但它也需要最近的用户交互,这是我关注的问题。当然,使用
    setData
    的优点是不需要解析HTML,也不需要为复制的数据创建DOM,在示例中就是这样是大量的数据,而且是实验性的

    以下截图显示了一个解决方案:(1)异步运行,(2)在必要时请求用户交互,(3)在可能的情况下使用setData,(3)如果
    setData
    不可用,则使用innerHTML->select.copy方法

    //此函数需要一个HTML字符串,并将其复制为富文本。
    // https://stackoverflow.com/a/34192073/12750353
    函数copyFormatted(html){
    //为HTML创建容器
    console.log('copyFormatted')
    变量c
    
    function onCopyCut(e) {
      if (!belongsToInput(e) || signalDOMEvent(cm, e))
        return;
      if (cm.somethingSelected()) {
        setLastCopied({
          lineWise: false,
          text: cm.getSelections()
        });
        if (e.type == "cut")
          cm.replaceSelection("", null, "cut")
      } else if (!cm.options.lineWiseCopyCut)
        return;
      else {
        var ranges = copyableRanges(cm);
        setLastCopied({
          lineWise: true,
          text: ranges.text
        });
        if (e.type == "cut")
          cm.operation(function() {
            cm.setSelections(ranges.ranges, 0, sel_dontScroll);
            cm.replaceSelection("", null, "cut")
          })
      }
      if (e.clipboardData) {
        e.clipboardData.clearData();
        var content = lastCopied.text.join("\n");
        e.clipboardData.setData("Text", content);
        if (e.clipboardData.getData("Text") == content) {
          e.preventDefault();
          return
        }
      }
      var kludge = hiddenTextarea(),
        te = kludge.firstChild;
      cm.display.lineSpace.insertBefore(kludge, cm.display.lineSpace.firstChild);
      te.value = lastCopied.text.join("\n");
      var hadFocus = document.activeElement;
      selectInput(te);
      setTimeout(function() {
        cm.display.lineSpace.removeChild(kludge);
        hadFocus.focus();
        if (hadFocus == div)
          input.showPrimarySelection()
      }, 50)
    }
    
    (function() {
        window._docs_chrome_extension_exists = !0;
        window._docs_chrome_extension_features_version = 1;
        window._docs_chrome_extension_permissions = "alarms clipboardRead clipboardWrite identity power storage unlimitedStorage".split(" ");
    }
    ).call(this);
    
    p.B_a = function(a) {
      var b = a.Ge().clipboardData;
      if (b && (b = b.getData("text/plain"),
          !be(Kf(b)))) {
        b = Lm(b);
        var c = this.C.getRange(),
          d = this.C.getRange();
        d.jq() && $fc(this.Fd(), d) == this.getValue().length && (c = this.Fd(),
          d = c.childNodes.length,
          c = TJ(c, 0 < d && XJ(c.lastChild) ? d - 1 : d));
        c.yP(b);
        VJ(b, !1);
        a.preventDefault()
      }
    };
    p.Z1b = function() {
      var a = this.C.getRange();
      a && 1 < fec(a).textContent.length && SAc(this)
    }
    
    p.bxa = function(a, b) {
      this.D = b && b.Ge().clipboardData || null;
      this.J = !1;
      try {
        this.rda();
        if (this.D && "paste" == b.type) {
          var c = this.D,
            d = this.L,
            e = {},
            f = [];
          if (void 0 !== c.items)
            for (var h = c.items, k = 0; k < h.length; k++) {
              var l = h[k],
                n = l.type;
              f.push(n);
              if (!e[n] && d(n)) {
                a: switch (l.kind) {
                  case "string":
                    var q = xk(c.getData(l.type));
                    break a;
                  case "file":
                    var t = l.getAsFile();
                    q = t ? Bnd(t) : null;
                    break a;
                  default:
                    q = null
                }
                var u = q;
                u && (e[n] = u)
              }
            }
          else {
            var z = c.types || [];
            for (h = 0; h < z.length; h++) {
              var E = z[h];
              f.push(E);
              !e[E] && d(E) && (e[E] = xk(c.getData(E)))
            }
            k = c.files || [];
            for (c = 0; c < k.length; c++) {
              u = k[c];
              var L = u.type;
              f.push(L);
              !e[L] && d(L) && (e[L] = Bnd(u))
            }
          }
          this.C = e;
          a: {
            for (d = 0; d < f.length; d++)
              if ("text/html" == f[d]) {
                var Q = !0;
                break a
              }
            Q = !1
          }
          this.H = Q || !And(f)
        }
        this.F.bxa(a, b);
        this.J && b.preventDefault()
      } finally {
        this.D = null
      }
    }
    
    //Button being a HTML button element
    button.addEventListener("click",function(){
      execCommand("copy");
    });
    
    //This function is called by a click or CMD/CTRL + C
    window.addEventListener("copy",function(e){
      e.preventDefault();  
      e.clipboardData.setData("text/plain", "Hey!");
    }