当前位置: 首页 > Web前端 > HTML

Typescript实现一键复制文本到剪贴板

时间:2023-03-28 15:45:02 HTML

Typescript实现一键复制文本到剪贴板场景在构建一些显示代码的页面时,一个常见的需求是点击一个按钮将页面的代码复制到剪贴板。目前Vue组合API工具库@vueuse/core提供useClipboard方法支持复制剪贴板功能,使用浏览器ClipboardAPI实现。核心代码是awaitnavigator!.clipboard.writeText(value)我的应用场景是在使用Vitepress+Typescript搭建组件库文档站的过程中,应用@vueuse/core实现点击按钮复制组件代码。在后续的测试中,发现在开发环境中点击按钮复制代码的功能是正常的,但是打包部署到生产环境后,点击按钮会提示复制失败,两个环境都使用了相同版本的Chrome浏览器。核心代码通过阅读@vueuse/core的源码,可以发现其isSupported判断函数使用了PermissionsAPI。核心判断方法permissionStatus=awaitnavigator!.permissions.query('clipboard-write')用于判断用户是否有对剪贴板的写权限。在生产环境中不支持isSupported判断的结果,但是在开发环境中是支持的。经过分析,发现在浏览器F12运行打包代码时,'clipboard'innavigator===false。回顾ClipboardAPI的MDN文档,有一个提示Securecontext:此功能仅在安全上下文(HTTPS)中可用,在部分或所有支持的浏览器中可用。这个关于stackoverflow的问题讨论这需要一个安全的来源——HTTPS或本地主机(或通过运行带有标志的Chrome来禁用)。就像ServiceWorker一样,此状态由navigator对象上的属性存在与否指示。结论是剪贴板API只支持在安全上下文(Securecontexts)下使用,安全上下文是指基于https协议或localhost/127.0.0.1本地环境访问的服务。但是在实际场景中,确实有服务需要部署在普通的http环境中,尤其是企业内部的一些项目,需要寻找ClipboardAPI的替代方案。在剪贴板API出现之前,主流的剪贴板操作是使用document.execCommand实现的;兼容性的思路是判断是否支持剪贴板,不支持则返回document.execCommand;document.execCommand实现一键复制记录当前页面的过程新建一个textarea,里面有focus/select的内容,把要复制的文本放到textarea.value中,把textarea插入到页面文档中,然后设置样式使其不影响已有页面的显示,将选中的textarea文本document.execCommand复制到剪贴板中并移除textarea从记录中恢复页面上原来选中的内容,实现代码复制代码。tsexportasyncfunctioncopyToClipboard(text:string){try{returnawaitnavigator.clipboard.writeText(text)}catch{constelement=document.createElement('textarea')constpreviouslyFocusedElement=document.activeElementelement.value=text//防止在移动设备上显示的键盘element.setAttribute('readonly','')element.style.contain='strict'element.style.position='absolute'element.style.left='-9999px'element.style.fontSize='12pt'//防止放大iOSconstselection=document.getSelection()constoriginalRange=selection?选择.rangeCount>0&&selection.getRangeAt(0):nulldocument.body.appendChild(element)element.select()//iOS的显式选择解决方法element.selectionStart=0element.selectionEnd=text.lengthdocument.execCommand('copy')document.body.body.removechild(element)if(ointersrange){selection!.removeallranges()//OriginalRange在选择是错误的选择!.addrange(OriginalRange)}//将焦点重新放在先前焦点的元素上时,这是真实的。,如果有的话if(previouslyFocusedElement){;(previouslyFocusedElementasHTMLElement).focus()}}}使用参考剪贴板APIPermissionsAPIdocument.execCommandgooglechrome-navigator.剪贴板未定义-堆栈溢出useClipboard|VueUsefix:在非安全上下文中复制代码(#792)·vuejs/vitepress@2935ed2