如何在单击后编程复制异步依赖内容到剪贴板?

12

我正在尝试在Chrome(Build 43)中编程使用execCommand,将异步JSONP请求的结果复制到剪贴板。这是逻辑的片段

loadContent()

function loadContent(callback) {
  $.getJSON('http://www.randomtext.me/api/lorem/p-5/10-20?&callback=myFunc',function(result){
    console.log('result=',result.text_out);
    $("#container").html(result.text_out);
    if (callback) {
      callback();
    }
  });
}

function copyAjax() {

 loadContent(copy);

}

function copy() {
  var copyDivText = $('#container').text();
  console.log('copyDivText=',copyDivText);
  executeCopy(copyDivText);
}

document.addEventListener("DOMContentLoaded", function(){
      document.getElementById("copy").onclick = copy;
    });


document.addEventListener("DOMContentLoaded", function(){
      document.getElementById("copyAjax").onclick = copyAjax;
    });


// Copy text as text
function executeCopy(text) {
    var input = document.createElement('textarea');
    document.body.appendChild(input);
    input.value = text;
    input.focus();
    input.select();
    document.execCommand('Copy');
    input.remove();
}

我知道从Chrome的构建版本43开始,你可以使用execCommand与剪贴板进行交互。然而,问题在于你需要在用户发起事件的执行过程中完成它(在这种情况下权限会被提升)。 这类似于基于Flash的解决方案ZeroClipboard所面临的限制。 除了得到一个“不可能”的答案(这是我现在思考的问题),以下是我想到的最后一招选项(警告,它们都是Hail Mary Passes):
  1. 由于JSONP无法同步,将其转换为使用普通AJAX调用的内容,并确保在用户事件执行上下文中该AJAX调用是同步的。这与我的深-rooted信念背道而驰,因为它会降低用户体验。
  2. 当用户靠近复制按钮时,我们会预先发送服务器请求,并希望在用户单击按钮之前速度足够快。这是一种明显的竞争条件,可能不是时间的一部分,并且对于想要使用Ctrl/Command-C而不是点击复制按钮的用户来说可能不起作用。
  3. 执行两个步骤的流程。一个点击以触发调用,当内容可用时,显示消息内容已经准备好,需要在消息区域再按一次点击以复制到剪贴板。这似乎不是最好的UX交互方式。我已经使用this example创建了此替代方案。通过程序触发点击并不构成用户事件。
  4. 可能有一种方法可以创建一个简单的Chrome扩展程序,并让用户设置该扩展程序的权限以复制到剪贴板。这涉及最终用户必须安装扩展程序并更改本地浏览器设置。不确定有多少用户能够/愿意这样做。

我已经查看了类似this的Stackoverflow问题,但它们并没有涉及到异步情况。如果您能找到其他可行的解决方案(或对现有解决方案进行微调),请告诉我。


你有没有想到这个问题的其他解决方案?我遇到了同样的情况,当用户请求复制时,我需要往返服务器从数据库中获取详细信息。使用你提供的三个建议似乎是四种劣势中最好的选择 :( .... - pythonator
执行两步操作。 我最近实现了这个功能。基本的用户体验是,当用户点击“获取链接”按钮时,您会发出ajax请求并显示一个旋转器。一旦请求完成,您将显示一个文本输入框以及一个小的复制按钮(类似于bootstrap css输入前置图标)。确保文本在输入框中自动选择。单击图标应将其复制到用户的剪贴板中。您可以调整交互以尽可能地使其美观(例如,我使输入在焦点进入时选择所有文本)。 - les2
1个回答

6
这是基于你的代码片段的工作超时处理方法:
HTML:
<div id="container">
Enter Text To Copy</br>
<textarea id="clipboard"></textarea>
</div>
<input type="button" value="Copy" id="copy"/>

JS:

var timeout = 600; // timeout based on ajax response time
var loaded = false;

function loadContent() {
  loaded = false;
  $.getJSON('http://codepen.io/gkohen/pen/QbvoQW.js',function(result){
    document.getElementById("clipboard").value = result.lorem;
    loaded = true;
  });
}

// Copy text as text
function copy() {
  clipboard = document.getElementById("clipboard");
  if (!loaded || clipboard.value.length == 0) {
    alert("Ajax timeout! TIP: Try to increase timeout value.");
    return;
  }

  clipboard.focus();
  clipboard.select();

  if (document.execCommand('Copy'))
    alert("Successfuly coppied to clipboard!");

  // set defaults
  clipboard.value = "";
  loaded = false;
}

document.addEventListener("DOMContentLoaded", function(){
  document.getElementById("copy").onmousedown = loadContent;
  document.getElementById("copy").onclick = function() {
    setTimeout(copy, timeout); // wait for ajax
  }
});

主要问题是execCommand规范。对于安全和可信操作存在一些限制。因此,你必须使事件调用复制和ajax调用分开。这可以通过固定超时(上面的代码)来完成或者通过可中断的休眠来完成。新的睡眠特性在这里被提到,也许可以通过clearTimeout修改为可中断的变体,但我没有尝试过。

也许你可以尝试一下我在这里提到的方法: 已解决:使用 AJAX 时 document execCommand copy 不起作用 - Nishanth Matha

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接