jQuery AJAX成功方法中无法复制剪贴板。

4

我想把银行卡号复制到剪贴板,以便在记事本中粘贴。我从互联网上得到的代码,在开发者工具栏中尝试非常好用。然而,如果我将该代码添加到我的Javascript文件并运行项目,则不起作用。以下是代码:

$.ajax({
  type: "POST",
  url: '@Url.Action("CopyToClipboard", "MyAccountSurface")',
  data: {
    controlId: controlId
  },
  dataType: 'json',
  success: function(data) {
    var $temp = $("<input>");
    $("body").append($temp);
    $temp.val(data.CardNumber).select();
    document.execCommand("copy");
    $temp.remove();
    alert('copied successfully');
  }
});

当您警告或在控制台中时,您可以获得 data.CardNumber 数据? - 4b0
是的,您需要确保 data.CardNumber 返回值正确。 - Bharatsing Parmar
是的,我懂了。 - user2746466
你不需要为了复制而附加临时字段。请看我的下面的答案。 - Buddybear
嘿,现在已经可以与用户交互了。请检查我的答案。 - Buddybear
7个回答

2

更新:

必须要有用户交互才能执行document.execCommand。所以在您的情况下,无法从AJAX响应中复制文本。这是浏览器同意的安全措施。

请参考W3C API

通过脚本API触发的复制和剪切命令只会影响真实剪贴板的内容,如果事件是由受信任并由用户触发的事件触发的,或者如果实现被配置为允许此操作。


通过用户交互的解决方法

添加步骤:

  • 使用相对位置将文本框放置在网页远离位置。
  • 添加一个处于禁用状态的按钮。一旦数据可用,重新启用该按钮。
  • 单击按钮后,您将能够执行document.execCommand,因为您直接与浏览器进行交互(因此没有API中提到的安全问题

$(document).ready(function() {
  $.ajax({
    url: 'https://jsonplaceholder.typicode.com' + '/posts/1',
    method: 'GET' 
  }).then(function(data) {
    console.log(data);
    $('#toBeCopied').val(data.title);
    $("#copyIt").attr('disabled', null);
  });

  
});
function copyToClipboard(){
    var $temp = $("<input />");
    $("body").append($temp);
    $temp.val($("#toBeCopied").val()).select();
    var result = false;
    try {
        result = document.execCommand("copy");
    } catch (err) {
        console.log("Copy error: " + err);
    }
    $temp.remove();
  }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<input type="text" value="dummy" id="toBeCopied" style="display:none; position: relative; left: -1000px;">
<b>Below button will be enabled once the data is available from AJAX</b>
<button id="copyIt" onclick="copyToClipboard()" disabled>Copy To Clipboard</button>


嗨,Gangadhar,如果你在JavaScript文件中尝试这个,它不起作用。在开发者工具栏控制台中可以正常工作。:( - user2746466
尝试在 ajax 调用之前创建一个隐藏字段,然后在 ajax 成功函数中设置该值,选择该元素,然后执行复制命令。 - Buddybear
仍然没有运气!:( - user2746466
嘿,它在没有jQuery的情况下工作,如果我添加jQuery,它就停止工作了。 - Buddybear
我无法删除jQuery。 - user2746466

2

如果你想通过Ajax在点击时复制到剪贴板

你将要点击的元素有几个事件:mousedownclick。它们按照这个顺序触发。这意味着你可以在第一个事件中发送ajax请求,在最后一个事件中处理结果,在这种情况下你不会有安全问题。

让我分享一个可行的例子:

  $link.on("mousedown", function() {
    var url = $(this).data("url");
    var $temp = $("<input id='copy_container' style='position:fixed;left:-200px;'>");

    $.ajax({
      url: url,
      dataType: "json",
      success: function (data) {
        $("body").append($temp);
        $temp.val(data.text);
      }
    })
  })

  $link.on("click", function() {
    setTimeout(function() {
      var $input = $("input#copy_container");
      if ($input.length && $input.val().length > 0) {
        $input.select();
        document.execCommand("copy");
        $input.remove();
      }
    }, 100)
  })

您需要在等待ajax响应时使用100ms的超时。可以根据您的需求进行改进。

固定和负位置 - 我认为您知道我们为什么需要它。


1
var response;

// recursively using setTimeout to wait for response 
var recCopy = function (){
    if(response){
        copy(response); 
        return;
    }     
    else {
        setTimeout(recCopy,2000); // for e.g. 2ms
    }
}

function copy(value) {
    var tempInput = document.createElement("input");
    tempInput.style = "position: absolute; left: -1000px; top: -1000px";
    tempInput.value = value;
    document.body.appendChild(tempInput);
    tempInput.select();
    try {
            var successful = document.execCommand('copy',false,null);
            var msg = successful ? 'successful' : 'unsuccessful';
            console.log('Copying text command was ' + msg);
        } catch (err) {
            alert('Oops, unable to copy to clipboard');
        }
    document.body.removeChild(tempInput);
}

$('.copyToClipboard').on('mousedown',function (e){
        $.ajax({
          url: "https://www.example.com/xyz",
          data: {
             formData :formData
          },
          type : 'post',
          success: function (data) {     
            response = data;  // on success, update the response
          } 
        }) 
});

$('.copyToClipboard').on('click',function (e){
    recCopy();
});

需要分别处理ajax调用和复制响应(例如,这里已处理了点击和按下事件)。
setTimeout可以递归使用来检查响应。一旦收到响应,就可以执行复制到剪贴板的操作。


1

你在复制什么?document.execCommand("copy"); 需要先选择(高亮)一些内容。

我认为在你的例子中,select 跟随 .val()。但是为了使其起作用,你需要选择一个元素,而不是它的值。

$temp.val(data.CardNumber);
$temp.select();

copied = document.execCommand("copy");
$temp.remove();

if(copied){
    alert('copied successfully');
}else{
    alert('something went wrong');
}

但是,为什么这段代码在ajax调用之外成功运行。如果我在cardnumber中添加硬编码值。 - user2746466
嗨Serg,复制的值为“false”。 - user2746466
如何使其适用于已发送的文本而非元素,因为我想要在运行时复制它,而不想将其存储在任何元素中。 - user2746466
@user2746466 我认为如果您在CSS中将新元素设置为display:none,您至少可以让用户感觉不像是仅为此而创建和删除一个元素。 - Serg Chernata
@user2746466,而且将$temp.remove();移到if语句中。尤其是假如你最终使用CSS视觉隐藏该字段。 - Serg Chernata
显示剩余5条评论

0

由于这不是用户交互,所以它将无法工作。

我们可以实现的解决方法是,在用户想要复制数据的区域鼠标进入时立即从ajax调用中获取数据,并将数据放置在某个文本区域或输入框中。

然后,在单击事件中,我们可以将数据复制到剪贴板中。

//按钮的mouseenter事件

$("#jq-copy-txt").on('mouseenter', function() {
    $.ajax({
      url: 'url',
      method: 'GET'
    }).then(function(data) {
       let copyFrom = document.getElementById("jq-cpy-txt-area"); 
        document.body.appendChild(copyFrom);
        copyFrom .textContent = data.title;
    });
});

// 用户触发的点击事件

$("#jq-copy-txt").on('click', function() {

   var fn = function() {
      let copyFrom = document.getElementsByTagName("textarea")[0];
      copyFrom.select();
      document.execCommand("copy");
    };
    setTimeout(fn, 1000);});

0

@Anton说的很好,但这都是不好的做法,因为您依赖于服务器在给定时间内给出响应,这是不好的。您可以看到所有具有复杂后端的大型网站都将其放入HTML对象中,以便用户可以通过ctrl+c或按钮单击进行复制。我会比Anton的方式稍微有所不同。

$('#btn').on('click', function(e){

    var url = 'Your-link.com';
    var $temp = $("<input id='copy_container' 
        style='position:fixed;left:-200px;'>");
    $.ajax({
      type: "POST",
      url: url,
      success: function(res) {
        $("body").append($temp);
        $temp.val(res);
      },
      error: function() {
         //handle error and do something
      }
    });
    setTimeout(function() {
        var $input = $("input#copy_container");
        if ($input.length && $input.val().length > 0) {
            $input.select();
            document.execCommand("copy");
            $input.remove();
        }
    }, 500)
});   

这样你就不需要重复使用事件监听器,但正如我之前所说,它远非完美。 最好将其放在向用户显示的HTML元素中。


0
这是我的做法。你可以从ajax调用返回成功后将值设置到剪贴板(第一个按钮),或者在需要时将文本从文本区域复制到剪贴板(第二个按钮)。
<div>
        <div>
            <label>Content</label>
        </div>
        <div>
            <button type="button" onclick="fnGenerate()">Retrieve and Copy To Clipboard</button>
        </div>
        <div>
            <button type="button" onclick="fnCopy()">Copy To Clipboard</button>
        </div>
        <div>
            <div>
                <textarea cols="50" rows="8" id="Content"></textarea>
            </div>
        </div>
    </div>

对于 JavaScript 部分

function fnGenerate() {
        $.ajax({                
            type: 'POST',
            dataType: 'json',
            ............
            ............
            url: 'someUrl',                  
            success: function (data, textStatus, xhr) {
                $('#Content').val(data);
                $('#Content').select();
                document.execCommand('copy');
            },
            error: function (xhr) {
                //Do Something to handle error
                var error = xhr.responseText;
            }
        });
    }

    function fnCopy() {
        $("#Content").select();
        document.execCommand('copy');
    }

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