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

发布时间:2025-12-10 11:20:56 浏览次数:2

  • 需用户先主动触发一个交互动作,才有权限复制文本。注意这里不能取巧,比如我创建一个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>
  • 模拟用户操作,调用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号方法。

  • 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);}

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

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

  • 需要做网站?需要网络推广?欢迎咨询客户经理 13272073477