5

所以我有一个按钮,它应该创建一个精美的共享 URL,使用 goo.gl 将其缩短,然后将其复制到剪贴板。好消息是,我已经成功地完成了所有这些,但不是一次全部完成。

问题源于规范:

从 document.execCommand() 触发的复制命令只会影响实际剪贴板的内容,如果该事件是从用户信任和触发的事件中分派的,或者如果实现被配置为允许这样做。如何配置实现以允许对剪贴板进行写访问超出了本规范的范围。

execCommand 非官方 W3C 规范

所以看来这可能行不通......

你看,为了缩短 URL,我需要进行 AJAX 调用。我只在用户单击共享按钮时才这样做,因为我每天有 1,000,000 个缩短的限制(如果每次页面更改时我都生成一个新的共享 URL,那么对于一个用户来说,这很容易成为 1,000 个新 URL,所以我d 限制为最多 1,000 名最终用户:不是最佳选择)。但这意味着我必须从发起事件的线程以外的线程监听 AJAX 事件,从而有效地失去了execCommand('copy').

有没有办法让一个单一的按钮既生成 goo.gl URL,然后将所述短 URL 复制到剪贴板?

作为参考,这是我写的 (Kotlin/JS)JavaScript 输出
这是一个SSCCE,它说明了它应该如何工作,但没有(基于陈杨华的回答)。

4

1 回答 1

3

有两种解决方案有效,但都有缺陷。一种仅在您的请求花费的时间少于一秒的情况下才有效,并且一种已被弃用,因此不应在生产环境中使用它。

第一个是使用setTimeout,这是为数不多的不会失去execCommand “特权”的异步函数之一。但它不会丢失,前提是它等于或小于 1000ms。因此,如果您的要求少于此要求,那么您就可以开始了,但如果不是,那么您就会出错。如果将它与某种超时处理结合起来,它可以工作,但如果请求经常花费超过 1 秒,那么它可能还不够好。像这样的例子:

var toCopy;

const buttonClick = () => {

  setTimeout(function() {
    if (toCopy) {
      // strangely, this execCommand will work
      console.log(document.execCommand('copy'));
    }
  }, 1000);

  var client = new XMLHttpRequest();
  client.onload = function(data) {

    toCopy = this.responseText;

  };

  // by setting your timeout on your request 
  // with the same duration as the setTiemout
  // you make sure it either works or throws an error
  client.ontimeout = function(data) {

    console.log('timeout');

  };
  client.timeout = 1000;
  client.open("GET", "https://www.random.org/integers/?num=1&min=1&max=100&col=1&base=10&format=plain");
  client.send();


}

$(() => {
  $("button").click(buttonClick)
})

document.addEventListener('copy', function(e) {

  e.preventDefault();
  e.clipboardData.setData('text/plain', toCopy);

});

https://jsfiddle.net/8md4Ltu2/4/

还有另一种让它工作的方法,但它已被弃用,所以不要使用。但是,为了彻底,我会把它放在这里。您可以将 XMLHttpRequest 的异步标志设置为 false。请求将是同步的,因此 execCommand 的处理非常简单。但是这个同步标志被弃用了,如果你尝试使用它,指导方针是抛出一个错误,所以它不被使用。见:https ://xhr.spec.whatwg.org/#synchronous-flag

var toCopy;

const buttonClick = () => {

  var client = new XMLHttpRequest();
  client.onload = function(data) {
    toCopy = this.responseText;
    console.log(document.execCommand('copy'));
  };


  client.open("GET", "https://www.random.org/integers/?num=1&min=1&max=100&col=1&base=10&format=plain", false);
  client.send();


}

$(() => {
  $("button").click(buttonClick)
})

document.addEventListener('copy', function(e) {

  e.preventDefault();
  e.clipboardData.setData('text/plain', toCopy);

});

https://jsfiddle.net/zezskm2x/2/

于 2018-03-07T19:44:11.270 回答