gpt4 book ai didi

前端实现复制文字和图片,原来这么简单!

转载 作者:我是一只小鸟 更新时间:2023-08-31 07:39:06 38 4
gpt4 key购买 nike

1.功能需求

实习工作中,遇到一个需求,需要完成点击复制的功能,当文字过长的时候,让用户手拖再ctrl+c这种方式体验就不是很好了,如果可以点击一下直接复制就是一种不错的优化用户体验的方式.

经过查阅文档,网络上完成这个功能大多使用两大类方法 。

第一种是以document.execCommand() 方法为主,无论是手写还是使用clipboard.js插件都是依赖的这个方法,但是在MDN 文档中已经显示过时了.

第二种是用了navigator.clipboard的方法,避免了过时问题,但是在复制图片的时候会有一定的浏览器兼容性问题 。

 2.document.execCommand('copy') 

这个方法其实就是在模拟用户选择元素然后右键复制的动作。尽管MDN已经显示这个方法过时了,但是仅针对copy这个指令,大部分主流浏览器都可以支持,所以这个方法仍然可以作为一种实现问题的方案.

2.1 基本用法

根据MDN文档学习本方法的传参和返回值 。

语法

                          
                            bool = document.execCommand(aCommandName, aShowDefaultUI, aValueArgument)
                          
                        

这个方法可以传3个参数,并且会返回一个布尔值 。

返回值

先从返回值开始,返回值相对比较简单,如果返回的值是false就表示浏览器不支持使用这个操作,反之浏览器支持该操作就返回true.

虽然这个返回值看似可以用来提前判断浏览器兼容性,但是 文档中不推荐在调用一个命令前,尝试使用返回值去校验浏览器的兼容性 。

参数值

参数一共可以传3个,但是使用复制命令的时候只需要传第一个参数就可以。这里简单介绍一下3个参数 。

  1. aCommandName:一个字符串类型的参数,是命令的名称,比如复制用到的copy,剪切用到的cut
  2. aShowDefaultUI:一个布尔类型的参数,表示是否展示用户界面,一般为false,Mozilla 没有实现
  3. aValueArgument:一些命令(例如 insertImage)需要额外的参数(insertImage 需要提供插入 image 的 url),默认为 null。

简单举例

以本文主要讲的复制命令为例子:document.execCommand('copy') 。

指令兼容性问题

前文讲到,MDN 不推荐在调用一个命令前,尝试使用返回值去校验浏览器的兼容性, 那么就需要用另外的方法去检测浏览器是否支持某个指令,浏览器为我们提供了一个方法叫document.queryCommandSupported(),使用这个方法可以检测浏览器是否支持某个指令,这个方法比较简单,只有1个参数,参数就传指令字符串,方法的返回值是一个布尔值表示当前浏览器是否支持这个指令.

举例如下:

  。

                          
                             if 
                            (document.queryCommandSupported && document.queryCommandSupported('copy'
                             )){ 
                             // 
                             先检测是否支持document.queryCommandSupported和copy指令 
                             // 
                             如果都支持直接执行指令 
                            
        document.execCommand('copy'
                             ) } 
                          
                        

  。

MDN文档中提到,document.queryCommandSupported也被弃用了,但是为了兼容性依然保留可用,当我们使用 document.execCommand的时候仍然可以用document.queryCommandSupported来检测是否支持。同时,它的浏览器兼容性也是比较好的,大部分主流浏览器都支持.

  。

2.2  Selection Api

复制文本这个操作对比复制图片是相对比较简单的,一共包含2大步 。

一是选中要复制的元素 。

二是执行复制指令.

执行复制指令在前面的基本语法里已经讲到了,直接调用document.execCommand('copy')就可以了。剩下要做的便是先选中元素了。下面便介绍一下和选中元素相关的selection api 。

MDN文档上写道:Selection   对象表示用户选择的文本范围或插入符号的当前位置。它代表页面中的文本选区,可能横跨多个元素。文本选区由用户拖拽鼠标经过文字而产生。如果要获取用于检查或修改的  Selection   对象,可以调用  window.getSelection()  方法.

这看起来就十分的官方和抽象,简单的来说 Selection 对象所对应的是用户所选择的  ranges  (区域),俗称  拖蓝 。上图中的拖蓝就是selection对象中的一个区域.

通过getRangeAt方法可以获取到具体的选中区域 。

                          
                                let selection = window.getSelection() 
                             // 
                             获取selection对象 
                            
    let range = selection.getRangeAt(0)  
                             // 
                             获取第一个选中的区域 
                          
                        

 除了获取选区中的区域之外,我们还可以通过  document.createRange() 创建一个新的区域,然后将该区域添加到选区中 。

                          
                             < 
                             body 
                             > 
                             < 
                             div 
                             id 
                             ="hello" 
                             > 
                            你好
                             </ 
                             div 
                             > 
                             < 
                             div 
                             id 
                             ="yes" 
                             > 
                            是的
                             </ 
                             div 
                             > 
                             </ 
                             body 
                             > 
                             < 
                             script 
                             > 
                             let selection 
                             = 
                             window.getSelection() 
                             // 
                             获取selection对象 
                             const hello 
                             = 
                             document.querySelector( 
                             ' 
                             #hello 
                             ' 
                             ) 
                             if 
                             (selection.rangeCount 
                             > 
                             0 
                             ){ 
                             // 
                             如果有已经选中的区域,直接全部去除 
                             selection.removeAllRanges() } let range 
                             = 
                             document.createRange() 
                             // 
                             创建range 
                             range.selectNode(hello) 
                             // 
                             range选中hello 
                             selection.addRange(range) 
                             // 
                             加入到选区中 
                             </ 
                             script 
                             > 
                          
                        

  。

效果如下,当代码执行后,你好这个元素被直接选中 。

加入区域的api包括range.selectNode和range.selectNodeContents。其中selectNode表示选中整个节点而selectNodeContents表示选中节点中的内容,针对文字的复制需要选中节点的内容,而图片的复制需要选中节点本身.

用法如下 。

                          
                             < 
                             body 
                             > 
                             < 
                             div 
                             id 
                             ="hello" 
                             > 
                            你好
                             </ 
                             div 
                             > 
                             < 
                             div 
                             id 
                             ="yes" 
                             > 
                            是的
                             </ 
                             div 
                             > 
                             < 
                             button 
                             class 
                             ="btn" 
                             > 
                            点击复制
                             </ 
                             button 
                             > 
                             </ 
                             body 
                             > 
                             < 
                             script 
                             > 
                             const yes 
                             = 
                             document.querySelector( 
                             ' 
                             #yes 
                             ' 
                             ) const selection 
                             = 
                             window.getSelection() const range 
                             = 
                             document.createRange() range.selectNode(yes) range.selectNode(yes) 
                             </ 
                             script 
                             > 
                          
                        

  。

  。

2.3复制文字

通过以上的selection api可以完成 创建selection对象-->选中节点内容-->添加到区域-->执行一下copy指令就可以完成复制文字了 。

                          
                             < 
                             body 
                             > 
                             < 
                             div 
                             id 
                             ="hello" 
                             > 
                            你好
                             </ 
                             div 
                             > 
                             < 
                             div 
                             id 
                             ="yes" 
                             > 
                            是的
                             </ 
                             div 
                             > 
                             < 
                             button 
                             class 
                             ="btn" 
                             > 
                            点击复制
                             </ 
                             button 
                             > 
                             </ 
                             body 
                             > 
                             < 
                             script 
                             > 
                             const btn 
                             = 
                             document.querySelector( 
                             ' 
                             .btn 
                             ' 
                             ) const hello 
                             = 
                             document.querySelector( 
                             ' 
                             #hello 
                             ' 
                             ) btn.addEventListener( 
                             ' 
                             click 
                             ' 
                             , () 
                             => 
                             { let range 
                             = 
                             document.createRange() 
                             // 
                             创建range 
                             range.selectNodeContents(hello) 
                             // 
                             range选中hello 
                             let selection 
                             = 
                             window.getSelection() 
                             // 
                             获取selection对象 
                             if 
                             (selection.rangeCount 
                             > 
                             0 
                             ) { 
                             // 
                             如果有已经选中的区域,直接全部去除 
                             selection.removeAllRanges() } selection.addRange(range) 
                             // 
                             加入到选区中 
                             if 
                             (document.queryCommandSupported 
                             && 
                             document.queryCommandSupported( 
                             ' 
                             copy 
                             ' 
                             )) { 
                             // 
                             先检测是否支持document.queryCommandSupported和copy指令 
                             // 
                             如果都支持直接执行指令 
                             document.execCommand( 
                             ' 
                             copy 
                             ' 
                             ) 
                             // 
                             去除选中区域,取消拖蓝效果 
                             selection.removeAllRanges() } }) 
                             </ 
                             script 
                             > 
                          
                        

  。

2.4复制图像

复制图像的操作是和复制文字基本相同的,只是需要在加入区域时选中整个节点,也就是把selectNodeContents方法换成selectNode 。

                          
                             < 
                             body 
                             > 
                             < 
                             div 
                             id 
                             ="hello" 
                             > 
                            你好
                             </ 
                             div 
                             > 
                             < 
                             div 
                             id 
                             ="yes" 
                             > 
                            是的
                             </ 
                             div 
                             > 
                             < 
                             img 
                             src 
                             ="./test.png" 
                             alt 
                             ="" 
                             > 
                             < 
                             button 
                             class 
                             ="btn" 
                             > 
                            点击复制
                             </ 
                             button 
                             > 
                             </ 
                             body 
                             > 
                             < 
                             script 
                             > 
                             const btn 
                             = 
                             document.querySelector( 
                             ' 
                             .btn 
                             ' 
                             ) const hello 
                             = 
                             document.querySelector( 
                             ' 
                             #hello 
                             ' 
                             ) const img 
                             = 
                             document.querySelector( 
                             ' 
                             img 
                             ' 
                             ) btn.addEventListener( 
                             ' 
                             click 
                             ' 
                             , () 
                             => 
                             { let range 
                             = 
                             document.createRange() 
                             // 
                             创建range 
                             range.selectNode(img) 
                             // 
                             range选中图像节点 
                             let selection 
                             = 
                             window.getSelection() 
                             // 
                             获取selection对象 
                             if 
                             (selection.rangeCount 
                             > 
                             0 
                             ) { 
                             // 
                             如果有已经选中的区域,直接全部去除 
                             selection.removeAllRanges() } selection.addRange(range) 
                             // 
                             加入到选区中 
                             if 
                             (document.queryCommandSupported 
                             && 
                             document.queryCommandSupported( 
                             ' 
                             copy 
                             ' 
                             )) { 
                             // 
                             先检测是否支持document.queryCommandSupported和copy指令 
                             // 
                             如果都支持直接执行指令 
                             document.execCommand( 
                             ' 
                             copy 
                             ' 
                             ) 
                             // 
                             去除选中区域,取消拖蓝效果 
                             selection.removeAllRanges() } }) 
                             </ 
                             script 
                             > 
                          
                        

  。

3.clipboard.js

clipboard.js是一个第三方库,也是使用了前文所讲到的document.execCommand('copy')来实现的点击复制,使用方便,但是只能用于文本的复制.

3.1安装和引入clipboard.js

使用npm安装 。

                          
                            npm install clipboard --save
                          
                        

安装后在html文件内引入 。

                          
                             < 
                             script 
                             src 
                             ="dist/clipboard.min.js" 
                             ></ 
                             script 
                             > 
                          
                        

或者使用CDN引入(这里只写了一种CDN引入方式,可以选择多种不同CDN方,具体请看 https://github.com/zenorocha/clipboard.js/wiki/CDN-Providers ) 。

                          
                             < 
                             script 
                             src 
                             ="https://cdn.jsdelivr.net/npm/clipboard@2.0.11/dist/clipboard.min.js" 
                             ></ 
                             script 
                             > 
                          
                        

使用import的方式引入 。

                          
                            import Clipboard from "clipboard";
                          
                        

3.2基本使用

初始化

直接创建一个ClipboardJS对象,传的参数可以是选择器字符串或者是DOM元素或者是DOM元素列表 。

                          
                             new 
                             ClipboardJS('.btn') 
                             // 
                             import方式为 new Clipboard('.btn') 
                          
                        

  。

实现点击复制文字功能

初始化完后,可以到要绑定的对应元素下添加data-clipboard-target属性,属性值是要复制的元素的选择器,这里要复制的元素是 ‘是的’ 那个div,所以属性值就写#yes。不进行其他配置时,我们点击按钮,触发点击事件后,就可以完成复制文字 ‘是的’ 了.

                          
                             < 
                             body 
                             > 
                             < 
                             div 
                             id 
                             ="hello" 
                             > 
                            你好
                             </ 
                             div 
                             > 
                             < 
                             div 
                             id 
                             ="yes" 
                             > 
                            是的
                             </ 
                             div 
                             > 
                             < 
                             button 
                             class 
                             ="btn" 
                             data-clipboard-target 
                             ="#yes" 
                             > 
                            点击复制
                             </ 
                             button 
                             > 
                             </ 
                             body 
                             > 
                             < 
                             script 
                             src 
                             ="https://cdn.jsdelivr.net/npm/clipboard@2.0.11/dist/clipboard.min.js" 
                             ></ 
                             script 
                             > 
                             < 
                             script 
                             > 
                             new 
                             ClipboardJS( 
                             ' 
                             .btn 
                             ' 
                             ) 
                             // 
                             import方式为 new Clipboard('.btn') 
                             </ 
                             script 
                             > 
                          
                        

 点击后,是的这个元素被选中(拖蓝),使用ctrl+v可以完成文字的复制,效果已经达到.

此时有2个问题需要优化 。

  1. 复制的内容必须是页面上的DOM元素,能不能是自己设定的?
  2. 拖蓝的效果不是很好看,如何复制文字不显示选中效果?

这时就要用到一个新的属性 data-clipboard-text ,属性值就是希望动态复制的内容。 对ClipboardJS绑定的元素设置这个属性就可以动态复制自己设定的内容,此时就不需要再设置data-clipboard-target属性了(如果同时写2个属性,data-clipboard-text优先)。以下代码是一个写死的简单展示,真实使用的时候属性值要用js设置成需要复制的值.

                          
                             < 
                             body 
                             > 
                             < 
                             div 
                             id 
                             ="hello" 
                             > 
                            你好
                             </ 
                             div 
                             > 
                             < 
                             div 
                             id 
                             ="yes" 
                             > 
                            是的
                             </ 
                             div 
                             > 
                             < 
                             button 
                             class 
                             ="btn" 
                             data-clipboard-text 
                             ="动态设置的内容" 
                             > 
                            点击复制
                             </ 
                             button 
                             > 
                             </ 
                             body 
                             > 
                             < 
                             script 
                             src 
                             ="https://cdn.jsdelivr.net/npm/clipboard@2.0.11/dist/clipboard.min.js" 
                             ></ 
                             script 
                             > 
                             < 
                             script 
                             > 
                             new 
                             ClipboardJS( 
                             ' 
                             .btn 
                             ' 
                             ) 
                             // 
                             import方式为 new Clipboard('.btn') 
                             </ 
                             script 
                             > 
                          
                        

 上图显示点击之后,复制内容成功,这样没有选中元素的效果,不会拖蓝,交互效果更好的同时又能动态设置内容 。

3.3更多用法

data-clipboard-action属性

data-clipboard-action属性可以决定执行的操作,这个属性有2个可选值copy或者是cut,默认是copy也就是复制,前面的所有代码中都没有出现这个属性,是直接使用的默认值copy。cut剪切,只能在input和textarea标签中使用,显然之前的div标签是无法使用的。使用方法仍是对ClipboardJS绑定的元素设置这个属性.

                          
                             < 
                             button 
                             class 
                             ="btn" 
                             data-clipboard-text 
                             ="动态设置的内容" 
                             data-clipboard-action 
                             ="copy" 
                             > 
                            点击复制
                             </ 
                             button 
                             > 
                          
                        

事件处理

事件处理可以让用户设置复制或剪切成功或者失败的回调,事件名分别是success和error。可以通过on在 ClipboardJS实例对象身上绑定success和error事件处理的回调。以下示例写了最简单alert打印成功和失败 。

                          
                                const clipboard = 
                             new 
                             ClipboardJS('.btn') 
                             // 
                             import方式为 new Clipboard('.btn') 
                            
    clipboard.on('success',
                             function 
                             (){ alert( 
                            '复制成功'
                             ) }) clipboard.on( 
                            'error',
                             function 
                             (){ alert( 
                            '复制失败'
                             ) }) 
                          
                        

纯JS写法

如果不想改HTML,加入过多的属性,可以直接使用纯JS写法来初始化ClipboardJS对象构造函数中传入第二个参数,第二个参数为对象,如下的示例中仅用完成js就完成了动态设置复制内容。设置配置对象的text方法,返回值就是要复制的内容 。

                          
                             new 
                             ClipboardJS('.btn'
                             ,{ text: 
                             function 
                             (){ 
                             return 
                             '动态复制的内容'
                             } }) 
                          
                        

设置配置对象的target方法,返回值就是要复制的元素 。

                          
                             new 
                             ClipboardJS('.btn'
                             ,{ target: 
                             function 
                             (){ 
                             return 
                             document.querySelector('#hello'
                             ) } }) 
                          
                        

经过测试,当html中设置属性的同时,又在构造函数里加入配置项,以js构造函数配置项为准(优先级高) 。

                          
                             < 
                             body 
                             > 
                             < 
                             div 
                             id 
                             ="hello" 
                             > 
                            你好
                             </ 
                             div 
                             > 
                             < 
                             div 
                             id 
                             ="yes" 
                             > 
                            是的
                             </ 
                             div 
                             > 
                             < 
                             button 
                             class 
                             ="btn" 
                             data-clipboard-target 
                             ="#hello" 
                             > 
                            点击复制
                             </ 
                             button 
                             > 
                             </ 
                             body 
                             > 
                             < 
                             script 
                             src 
                             ="https://cdn.jsdelivr.net/npm/clipboard@2.0.11/dist/clipboard.min.js" 
                             ></ 
                             script 
                             > 
                             < 
                             script 
                             > 
                             new 
                             ClipboardJS( 
                             ' 
                             .btn 
                             ' 
                             ,{ target(){ 
                             return 
                             document.querySelector( 
                             ' 
                             #yes 
                             ' 
                             ) } }) 
                             </ 
                             script 
                             > 
                          
                        

销毁对象

如果使用的是单页应用程序,可能希望更精确地管理DOM的生命周期。可以使用destroy方法销毁对象 。

                          
                             var 
                             clipboard = 
                             new 
                             ClipboardJS('.btn'
                             ); clipboard.destroy(); 
                          
                        

3.4源码分析

看了之前的api,想了解一下这个所谓的简单的复制库是如何实现的,于是打开了源码开始分析一下 。

源码地址 https://github.com/zenorocha/clipboard.js 。

初始化

构造函数里面传2个参数,第一个trigger即触发点击的元素对象,第二个options配置项。从最简单的例子来看,只需要传一个trigger参数就可以实现功能,那就先不管options,直接看与trigger有关的listenClick方法.

listenClick方法调用了一个第三方库的listen方法绑定了click事件和对应的回调函数this.onClick,在onclick方法中,调用了ClipboardActionDefault方法,并且传了对应的几个配置项参数,action container,target,text,这些值都是this.xxx方法,这几个方法又是在哪定义的呢?

  。

找了一下类内部,定义这些方法的地方是在前文构造函数里的 this.resolveOptions方法里 。

resolveOptions方法里的defaultAction,defaultText等等方法都是类似的,都是调用了一个getAttributeValue方法去获取html模板上的属性值 。

getAttributeValue方法如下,比较简单  。

ClipboardActionDefault

上面跳了这么多方法虽然不难,但是也有点绕,主要还是在干一件事,那就是通过定义来准备好 ClipboardActionDefault这个方法的参数。这时候就要看一下ClipboardActionDefault这个方法在干什么.

简单来看,这个方法主要分4个if判断,前2个if就是一些条件的判断,判断action只能是复制或者剪切,还有就是判断要复制的目标节点的节点类型和readonly问题等等,此处不展开去研究,有兴趣者可以点击本部分开始处的源码链接下载.

后2个if判断中的内容如下,分别用于判断是否有text值和target值,这2个值也是通过本库的核心属性data-clipboard-text和data-clipboard-target在html中获取的(或者在js配置项里获取)。判断完后就调用了ClipboardActionCopy或者ClipboardActionCut方法去实现复制或者剪切功能.

ClipboardActionCopy

这个方法就开始进行文本的复制了,首先判断要复制的目标是普通的字符串(通过data-clipboard-text设置)还是节点(通过data-clipboard-target设置),如果是文本或者不是普通的输入元素,直接调用 fakeCopyAction方法执行复制操作.

  。

 fakeCopyAction先创建了虚拟元素,然后把这个元素插入dom里,最后执行选中+复制操作 。

创建虚拟元素的方法也比较简单,先通过原生方法createElement创建了一个textarea元素,然后把它隐藏。创建这种输入类元素的好处就是可以直接去修改它的value,最后一步操作就是把文本text赋值给textarea 。

 创建完虚拟元素就要处理选中问题了,这里调用了select方法,方法内部根据3种元素类型设置了不同的处理对策,select元素只要focus后赋值就好。输入元素可以调用原生的select方法来选中元素,而普通元素就需要使用之前讲到的selection api去获取range和添加range了 。

                          
                             function 
                             select(element) { 
                             var 
                             selectedText; 
                             if 
                             (element.nodeName === 'SELECT'
                             ) { 
                             // 
                             针对select元素的处理 
                             element.focus(); selectedText 
                            =
                             element.value; } 
                             else 
                             if 
                             (element.nodeName === 'INPUT' || element.nodeName === 'TEXTAREA'
                             ) { 
                             // 
                             选中输入元素 
                             var 
                             isReadOnly = element.hasAttribute('readonly'
                             ); 
                             if 
                             (!
                             isReadOnly) { element.setAttribute( 
                            'readonly', ''
                             ); } element.select(); element.setSelectionRange( 
                            0
                             , element.value.length); 
                             if 
                             (!
                             isReadOnly) { element.removeAttribute( 
                            'readonly'
                             ); } selectedText 
                            =
                             element.value; } 
                             else 
                             { 
                             // 
                             普通元素选中 
                             if 
                             (element.hasAttribute('contenteditable'
                             )) { element.focus(); } 
                             var 
                             selection =
                             window.getSelection(); 
                             var 
                             range =
                             document.createRange(); range.selectNodeContents(element); selection.removeAllRanges(); selection.addRange(range); selectedText 
                            =
                             selection.toString(); } 
                             return 
                             selectedText; } 
                          
                        

最后的command('copy')也就是对执行复制指令这个方法的简单封装,做了一下兼容性的处理.

4. navigator.clipboard

前面的document.execCommand和第三方库clipboard.js都非常的好用,但是他们可能面临被弃用的风险,那么该怎么解决复制粘贴这个问题呢? H5新推出的clipboard api是 处理复制粘贴相关的api,可以很好的解决这个问题。用promise的方式把数据写入剪贴板,避免了页面的卡顿.

4.1 复制文字

Clipboard对象

使用Clipboard api时我们不需要手动创建Clipboard对象,而是通过navigator.clipboard来获取 。

打印出Clipboard对象后可以看出,这个对象有4个方法,分为两大类,write和read类。其中与复制相关的是write类表示把数据写入剪贴板,和粘贴相关的是read类表示从剪贴板里面读取数据 。

 writeText方法

Clipboard对象中的writeText方法可以用于复制文字,也是非常简单易用的一个方法.

参数:传一个字符串参数,即要复制的内容 。

返回值: 一个promise对象,如果成功复制则是成功的promise,如果写入剪贴板失败(复制失败)则是失败的promise 。

示例如下:先创建了一个clipboard对象,然后直接调用writeText方法复制文字123 。

                          
                            navigator.clipboard.writeText('123')
                          
                        

根据之前的html结构,使用Clipboard api完成文字的复制 。

默认情况下,会为当前的激活的页面自动授予剪贴板的写入权限。出于安全方面考虑,这里我们还是先主动向用户请求剪贴板的写入权限,如果被授权,就可以调用上面的方法直接完成复制了.

                          
                             < 
                             body 
                             > 
                             < 
                             div 
                             id 
                             ="hello" 
                             > 
                            你好
                             </ 
                             div 
                             > 
                             < 
                             div 
                             id 
                             ="yes" 
                             > 
                            是的
                             </ 
                             div 
                             > 
                             < 
                             img 
                             src 
                             ="./test.png" 
                             alt 
                             ="" 
                             > 
                             < 
                             button 
                             class 
                             ="btn" 
                             > 
                            点击复制
                             </ 
                             button 
                             > 
                             </ 
                             body 
                             > 
                             < 
                             script 
                             > 
                             const btn 
                             = 
                             document.querySelector( 
                             ' 
                             .btn 
                             ' 
                             ) const hello 
                             = 
                             document.querySelector( 
                             ' 
                             #hello 
                             ' 
                             ) const img 
                             = 
                             document.querySelector( 
                             ' 
                             img 
                             ' 
                             ) btn.addEventListener( 
                             ' 
                             click 
                             ' 
                             , async () 
                             => 
                             { const { state } 
                             = 
                             await navigator.permissions.query({ 
                             // 
                             出于安全方面考虑,这里我们还是主动向用户请求剪贴板的写入权限 
                             name: 
                             " 
                             clipboard-write 
                             " 
                             , }); 
                             if 
                             (state 
                             == 
                             ' 
                             granted 
                             ' 
                             ) { navigator.clipboard.writeText(hello.innerHTML) } }) 
                             </ 
                             script 
                             > 
                          
                        

  。

4.2 复制图像

write方法

write方法除了支持文本数据之外,还支持将图像数据写入到剪贴板,调用该方法后会返回一个 Promise 对象.

以下是简单的使用案例,先通过 Blob API 创建 Blob 对象,然后使用该 Blob 对象来构造 ClipboardItem 对象,最后再通过 write 方法把数据写入到剪贴板,复制了文字(当前页面的地址) 。

                          
                             < 
                             button 
                             onclick 
                             ="copyPageUrl()" 
                             > 
                            拷贝当前页面地址
                             </ 
                             button 
                             > 
                             < 
                             script 
                             > 
                             async 
                             function 
                             copyPageUrl() { const text 
                             = 
                             new 
                             Blob([location.href], {type: 
                             ' 
                             text/plain 
                             ' 
                             }); 
                             try 
                             { await navigator.clipboard.write( 
                             new 
                             ClipboardItem({ 
                             " 
                             text/plain 
                             " 
                             : text, }), ); console.log( 
                             " 
                             页面地址已经被拷贝到剪贴板中 
                             " 
                             ); } 
                             catch 
                             (err) { console.error( 
                             " 
                             页面地址拷贝失败: 
                             " 
                             , err); } } 
                             </ 
                             script 
                             > 
                          
                        

复制图片案例

了解了write的基本用法,那使用Clipboard对象复制图片也有办法了,只要先把图像变成Blob对象,然后构造 ClipboardItem 对象,最后再调用write方法就好.

可是,如何把一个img标签里的图片转换成Blob对象呢?

首先从Blob对象的构造函数开始, MDN文档 写了Blob构造函数所需要的参数 。

                          
                            var aBlob = new Blob( array, options );
                          
                        

array 是一个由ArrayBuffer, ArrayBufferView, Blob, DOMString 等对象构成的 Array ,或者其他类似对象的混合体,它将会被放进 Blob。DOMStrings 会被编码为 UTF-8。 options 是一个可选的BlobPropertyBag字典,它可能会指定如下两个属性:

  1. type,默认值为 "",它代表了将会被放入到 blob 中的数组内容的 MIME 类型。
  2. endings,默认值为"transparent",用于指定包含行结束符\n的字符串如何被写入。它是以下两个值中的一个:"native",代表行结束符会被更改为适合宿主操作系统文件系统的换行符,或者 "transparent",代表会保持 blob 中保存的结束符不变

  。

根据文档中显示,我们需要先准备一个对应的数组,然后才能构造Blob对象,也就是要把图片转成二进制数据.

分步骤实现把图片转换成Blob 。

  1. 把img图像画在canvas画布上
  2. 调用canvas的toDataURL方法,获取图片的base64编码
  3. 调用atob方法,把base64编码的数据转换成二进制数据
  4. 根据转换后的二进制数据,创建一个视图,此视图将把缓冲内的数据格式化为一个 8 位无符号整数数组,也就是获得了一个ArrayBufferView数组(关于ArrayBuffer和ArrayBufferView的内容详细可查阅  JavaScript 类型化数组 )

  。

下方代码完成了基本的功能实现:

  。

 微信输入框显示,可以完成复制 。

这个方法在浏览器兼容性上仍存在一些问题,比如火狐可能就不支持ClipboardItem对象,此时只能用前文写的document.execCommand方法了.

                          
                             < 
                             body 
                             > 
                             < 
                             div 
                             id 
                             ="hello" 
                             > 
                            你好
                             </ 
                             div 
                             > 
                             < 
                             div 
                             id 
                             ="yes" 
                             > 
                            是的
                             </ 
                             div 
                             > 
                             < 
                             img 
                             style 
                             ="width: 400px; height: 200px" 
                             src 
                             ="./test.png" 
                             alt 
                             ="" 
                             > 
                             < 
                             button 
                             class 
                             ="btn" 
                             > 
                            点击复制
                             </ 
                             button 
                             > 
                             </ 
                             body 
                             > 
                             < 
                             script 
                             > 
                             const btn 
                             = 
                             document.querySelector( 
                             ' 
                             .btn 
                             ' 
                             ) const hello 
                             = 
                             document.querySelector( 
                             ' 
                             #hello 
                             ' 
                             ) const img 
                             = 
                             document.querySelector( 
                             ' 
                             img 
                             ' 
                             ) btn.addEventListener( 
                             ' 
                             click 
                             ' 
                             , async () 
                             => 
                             { const { state } 
                             = 
                             await navigator.permissions.query({ 
                             // 
                             出于安全方面考虑,这里我们还是主动向用户请求剪贴板的写入权限 
                             name: 
                             " 
                             clipboard-write 
                             " 
                             , }); 
                             if 
                             (state 
                             == 
                             ' 
                             granted 
                             ' 
                             ) { 
                             // 
                             创建canvas对象 
                             const canvas 
                             = 
                             document.createElement( 
                             ' 
                             canvas 
                             ' 
                             ); const context 
                             = 
                             canvas.getContext( 
                             ' 
                             2d 
                             ' 
                             ); const image 
                             = 
                             new 
                             Image() image.src 
                             = 
                             img.src image.onload 
                             = 
                             async () 
                             => 
                             { canvas.width 
                             = 
                             image.width; canvas.height 
                             = 
                             image.height; context.drawImage(image, 
                             0 
                             , 
                             0 
                             , image.width, image.height); 
                             // 
                             img图片转成canvas 
                             const imageDataUrl 
                             = 
                             canvas.toDataURL() 
                             // 
                             通过canvas获取base64编码 
                             const binary 
                             = 
                             atob(imageDataUrl.split( 
                             ' 
                             , 
                             ' 
                             )[ 
                             1 
                             ]); 
                             // 
                             base64编码转二进制数据 
                             const array 
                             = 
                             []; 
                             for 
                             (let i 
                             = 
                             0 
                             ; i 
                             < 
                             binary.length; i 
                             ++ 
                             ) { array.push(binary.charCodeAt(i)); } 
                             // 
                             二进制数据转Blob对象 
                             const blob 
                             = 
                             new 
                             Blob([ 
                             new 
                             Uint8Array(array)], { type: 
                             ' 
                             image/png 
                             ' 
                             }); 
                             // 
                             判断浏览器是否有ClipboardItem对象,有些浏览器不支持本方法 
                             if 
                             ( 
                             typeof 
                             ClipboardItem 
                             !== 
                             ' 
                             undefined 
                             ' 
                             ) { 
                             // 
                             把blob数据写入剪贴板 
                             await navigator.clipboard.write([ 
                             new 
                             ClipboardItem({ [blob.type]: blob }) ]) } } } }) 
                             </ 
                             script 
                             > 
                          
                        

  。

  。

最后此篇关于前端实现复制文字和图片,原来这么简单!的文章就讲到这里了,如果你想了解更多关于前端实现复制文字和图片,原来这么简单!的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。

38 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com