文档 execCommand 副本不适用于 AJAX

Posted

技术标签:

【中文标题】文档 execCommand 副本不适用于 AJAX【英文标题】:document execCommand copy not working with AJAX 【发布时间】:2017-09-08 21:45:05 【问题描述】:

无法直接复制生成的链接(不用ctrl+C) 我是usign document.execCommand('copy'),但似乎没有效果。 如果代码没有 AJAX,那么它可以正常工作。 这里是

fiddle link with AJAX

fiddle link without AJAX

HTML

<div class="permalink-control"> </div>

JQUERY

    $(".permalink-control")
          .append(
            '<div class="input-group">' +
            '    <span class="input-group-btn"><button type="button" class="btn btn-default" title="Get Permalink"><span class="glyphicon glyphicon-link"></span></button></span>' +
            '    <input type="text" class="form-control">' +
            '</div>'
          );
        $(".permalink-control input")
          .hide()
          .focus(function () 
            // Workaround for broken selection: https://***.com/questions/5797539
            var $this = $(this);
            $this.select()
              .mouseup(function () 
                $this.unbind("mouseup");
                return false;
              );
          );
        $(".permalink-control button")
          .click(function () 
            var $this = $(this);
            $.ajax(
              url: "https://api-ssl.bitly.com/shorten",
              dataType: "jsonp",
              data: 
                longUrl: window.location.href,
                access_token: "your access token",
                format: "json"
              ,
              success: function (response) 
                var longUrl = Object.keys(response.results)[0];
                var shortUrl = response.results[longUrl].shortUrl;
                if (shortUrl.indexOf(":") === 4) 
                  shortUrl = "https" + shortUrl.substring(4);
                
                $this.parents(".permalink-control")
                  .find("input")
                  .show()
                  .val(shortUrl)
                  .focus();
              ,
              async:false
            );
          );

更新:

How do I copy to the clipboard in javascript?

不回答我的问题,因为如果 AJAX 不存在,我的代码也会在不使用 ctrl+C 的情况下复制。 但是,当我使用 AJAX 时,document.execCommand('copy') 不起作用。

【问题讨论】:

@AndreiGheorghiu 复制工作,只是当你点击按钮时不行。 我的代码也直接复制链接。但是当我使用 AJAX 时。链接没有被复制。 @AndreiGheorghiu 你找到了一个不相关的答案。当您直接单击输入时,复制工作,而不是当您单击其他按钮(如按钮)时。更不用说答案已经很老了,而且现在完全不相关了。 @AndreiGheorghiu 我已经知道这个答案仔细阅读我的问题 您唯一的选择是在用户单击时填充输入值。 this possible 在您的用例中吗?如果您不想在每次页面加载时触发对$.ajax() 的调用,请在按钮周围设置一个更大的不可见元素,并在鼠标进入不可见元素时触发 ajax。不是防弹的,但总比没有好。一个好的技巧可能是将按钮放在下拉菜单、抽屉、弹出窗口、模式或工具提示中。当用户打开它时,在它打开之前得到响应。并在 ajax 返回之前禁用按钮。 【参考方案1】:

原因在W3 specs中有明确说明:

通过脚本 API 触发的复制和剪切命令只会影响实际剪贴板的内容,前提是该事件是从用户信任和触发的事件分派的,或者如果实施配置允许这样做。

但是,话虽如此,我们可以尝试通过复制文本 when a user does some interaction 来绕过浏览器。

在这种情况下,由于您正在寻找 click 事件,我假设您的用户正在与 mouse 进行交互

那么,如果我在 ajax 调用解决后附加一个 $(window).blur()$(document).click() 事件呢?

没错,由于用户在某些时候必须blur 才能使用复制选择,因此用户将发起blur() or click() (depending on your need),我们可以将文本复制到剪贴板。

这是HACKY DEMO

$(document).ready(function()
    var shortUrl;
    $(".permalink-control")
      .append(
        '<div class="input-group">' +
        '    <span class="input-group-btn"><button type="button" class="btn btn-default" title="Get Permalink"><span class="glyphicon glyphicon-link"></span></button></span>' +
        '    <input type="text" class="form-control">' +
        '</div>'
      );
     $(".permalink-control input")
      .hide()
      .focus(function () 
        // Workaround for broken selection: http://***.com/questions/5797539
        var $this = $(this);
        $this.select();
        document.execCommand('copy');
          $this.mouseup(function () 
            $this.unbind("mouseup");
            return false;
          );
      );
    $(".permalink-control button")
      .click(function () 
        var shortUrl ="";
        var $this = $(this);
        $.ajax(
          url: "https://api-ssl.bitly.com/shorten",
          dataType: "jsonp",
          data: 
            longUrl: window.location.href,
            access_token: "48ecf90304d70f30729abe82dfea1dd8a11c4584",
            format: "json"
          ,
          success: function (response) 
             var longUrl = Object.keys(response.results)[0];
            shortUrl = response.results[longUrl].shortUrl;
            if (shortUrl.indexOf(":") === 4) 
              shortUrl = "https" + shortUrl.substring(4);
            
              $this.parents(".permalink-control")
              .find("input")
              .show()
              .val(shortUrl)
              .focus();
             
       ).done(function()
            $(window).blur(function()
							document.execCommand('copy');
              $(window).off('blur');// make sure we don't copy anything else from the document when window is foucussed out
            );
       )
    );
)
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="permalink-control"></div> 
<div class"log"></div>

P.S:这已经在 chrome 中测试过了。

【讨论】:

如果 click 事件在当前选项卡中,我可以使用它,但它如何与 onblur 一起使用?在 onblur 事件期间,由于指针进入新界面,选择存储被清除。 适用于 IE 11,不适用于 Chrome 63.x、Firefox 57.x【参考方案2】:

我遇到了同样的问题。我相当原始地解决了它:在单击事件的处理程序中,您可以运行一个间隔,该间隔将检查服务器响应后 ajax 将在其中插入值的变量。收到答案后,我们停止间隔并开始使用剪贴板工作。没问题,因为用户自己在点击后开始间隔,没有任何回调。

简单的jQuery示例:

var ajaxResponse;

function copyText(copiedText)
  $('<textarea class="copied-text">' + copiedText + '</textarea>').appendTo('body');

  if ( navigator.userAgent.match(/ipad|iphone/i) ) 
    var range = document.createRange(),
        textArea = $('.copied-text')[0];
    range.selectNodeContents(textArea);
    var selection = window.getSelection();
    selection.removeAllRanges();
    selection.addRange(range);
    textArea.setSelectionRange(0, 999999);
   else 
    $('.copied-text').select();
  

  document.execCommand('copy');
  $('.copied-text').remove();
;

function myAjaxFunc()
  $.ajax(
    type: 'POST',
    url: yourUrl,
    data: yourData,
    success: function(data)
      ajaxResponse = data;
    
  );
;

$('.your-button').on('click', function()
  myAjaxFunc();
  var ajaxCheckTimer = setInterval(function()
    if ( ajaxResponse ) 
      copyText(ajaxResponse);
      clearInterval(ajaxCheckTimer);
    ;
  , 100);
);

在这个例子中,当点击一个按钮时,我们会向服务器发送一些数据,并通过检查 ajaxResponse 变量的值来启动间隔。

收到服务器的响应后,将服务器的响应写入此变量,之后区间内的条件为真并调用文本复制函数,并将服务器响应变量指定为参数:copyText(ajaxResponse);。间隔停止。

copyText 函数使用ajaxResponse 变量的值在页面上创建一个文本区域,将该值从字段复制到剪贴板,然后从页面中删除该字段。

更新 01.07.19

为了在 ios 上正确复制到剪贴板,请将属性 contenteditable 与值true 添加到文本字段:

$('<textarea class="copied-text" contenteditable="true">' + copiedText + '</textarea>').appendTo('body');

【讨论】:

以上是关于文档 execCommand 副本不适用于 AJAX的主要内容,如果未能解决你的问题,请参考以下文章

Google Container Engine (Kubernetes):Websocket (Socket.io) 不适用于多个副本

有啥比 document.execCommand 更好的吗?

用于 iOS webView 中标题的 document.execCommand

为啥 firebase_firestore 安全规则不适用于文档读取

textarea 不适用于具有值的文档加载

是否有理由不将 JSONP 用于 AJA~X 请求?