JS封装复制文本内容到剪贴板的方法

  1. 需用户先主动触发一个交互动作,才有权限复制文本。注意这里不能取巧,比如我创建一个dom,然后调用click之类的dom原生方法,并监听click事件,在click事件回调写下面的代码,最后在把这个dom移除。实测是不行的,必须触发源是用户使用硬件与UI交互才行。也就是下面代码要执行在事件回调中。
    const copyFunc = (str) => {
      navigator.clipboard.writeText(str);
    }

    navigator.clipboard.writeText方法返回一个Promise对象实例。

    如果使用iframe跨域的情况需要启用Permissions Policy,在创建iframe的dom对象时给allow属性赋值“clipboard-write”启用剪贴板写的权限, 需要读的权限则再加上“clipboard-read”。若已经挂载到domtree中并在html中被渲染后,再使用控制台更改allow属性是不行的,会被浏览器视为无权限。

    <iframe src="" width="100%" height="100%" allow="clipboard-read; clipboard-write">
        ...
    </iframe>
  2. 模拟用户操作,调用document.execCommand("copy")的API,这里提供两种思路,一种是强制给ClipboardEvent对象强制写入值,但注意要阻止默认事件,否则会被复写。代码如下:

    const copyFunc = (str) => {
      const inject = e => {
        e.preventDefault();
        e.clipboardData && e.clipboardData.setData("text/plain", str);
        document.removeEventListener("copy", inject, false);
      }
      document.addEventListener("copy", inject, false);
      document.execCommand("copy");
    }

    另一种思路是创建一个文本选区,然后再执行document.execCommand("copy")复制文本,这个实现和用户实际操作非常接近了,以下提供两种方法。

    这里可以用document.createRange方法来创建一个选区,代码如下:

    const copyFunc = (str) => {
      // 随便创建一个html元素dom对象,并挂载到domtree上
      const oDom = document.createElement("span");
      document.body.appendChild(oDom);
      oDom.textContent = str;
      // 先清除所有选区
      const selection =  window.getSelection();
      selection?.removeAllRanges(); // 如果想先判断可以看selection对象上rangeCount属性
      // 创建range选区对象,并建立选区
      const range = document.createRange();
      range.selectNode(oDom);
      // 把range对象挂载到浏览器的选区中
      selection?.addRange(range);
      // 执行复制
      document.execCommand("copy");
      // 移除dom对象
      document.body.removeChild(oDom);
    }

    假如我们创建的dom是input元素,还可以取一个巧,调用dom的API——select方法,可以直接创建一个本文选区,可以少写一些代码。代码如下:

    const copyFunc = (str) => {
      const oDom = document.createElement("input");
      oDom.value = str;
      document.body.appendChild(oDom);
      oDom.select();
      document.execCommand("copy");
      document.body.removeChild(oDom);
    }

    document.execCommand这个API目前浏览器还支持,但由于安全问题在新规范中这个API已经被移除了,兴许某天浏览器不再兼容也说不定。官方给出的代替方案就是本文的1号方法。

  3. Chrome内核浏览器有个API——document.dispatchEvent,这个API可以模拟触发一个事件,现在我们将用它来代替document.execCommand方法。另w3c规范中提供了构造函数ClipboardEvent来创建一个剪贴板事件对象,这个规范已经在各大浏览器中实践了可以正常使用。如果模拟一个自定义的copy事件应该能实现吧:

    const copyFunc = (str) => {
      const clipboardEvent = new ClipboardEvent("copy", {
        clipboardData: new DataTransfer("text/plain", str)
      });
      document.dispatchEvent(clipboardEvent);
    }

    实测不能,那如果仅模拟触发一个copy事件,再回调中用setData方法注入数据,也许能行?

    const copyFunc = (str) => {
      const clipboardEvent = new ClipboardEvent("copy");
      const inject = e => {
        e.clipboardData && e.clipboardData.setData("text/plain", str);
        document.removeEventListener("copy", inject, false);
      }
      document.addEventListener("copy", inject, false);
      document.dispatchEvent(clipboardEvent);
    }

    事件实测是可以触发的,也可以打印出这个e参数;但实际这个e.clipboardData的值为null,所以压根不会执行后面的方法。再优化一下:

    const copyFunc = (str) => {
      const clipboardEvent = new ClipboardEvent("copy", {
        clipboardData: new DataTransfer("text/plain", "")
      });
      const inject = e => {
        // e.preventDefault() 这里已经当作默认事件处理了,加不加不影响
        e.clipboardData && e.clipboardData.setData("text/plain", str);
        document.removeEventListener("copy", inject, false);
      }
      document.addEventListener("copy", inject, false);
      document.dispatchEvent(clipboardEvent);
    }

    很遗憾,实测依然不行。具体原因未知,但思路应该没有问题,如果有知道怎么解决的还请告知。

    以上。实现很简单,但管理各种库才是麻烦事!尽量少用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值