资讯专栏INFORMATION COLUMN

js获取剪切板内容,js控制图片粘贴。

KaltZK / 2566人阅读

摘要:在用户执行粘贴操作的时候,能够获得剪切板的内容,本文讨论一下这个问题。目前只有支持获取剪切板中的图片数据。这么多的判断条件,基本可以确定通过剪切板过来的是粘贴的文件。

在用户执行粘贴操作的时候,js能够获得剪切板的内容,本文讨论一下这个问题。

目前只有Chrome支持获取剪切板中的图片数据。还好需要这个功能的产品目前只支持ChromeSafari,一些Chrome的新特性是可以尽情使用了,还是能够覆盖到大部分用户的。所以本文只讨论Chrome如何使用和如何阻止Safari,原理大概了解了,再研究其他浏览器相关的问题就容易多了。

paste事件

可以用js给页面中的元素绑定paste事件的方法,当用户鼠标在该元素上或者该元素处于focus状态,绑定到paste事件的方法就运行了。

绑定的元素不一定是input,普通的div也是可以绑定的,如果是给document绑定了,就相当于全局了,任何时候的粘贴操作都会触发。

事件对象 获取事件对象

先写一下事件绑定的代码

pasteEle.addEventListener("paste", function (e){
    if ( !(e.clipboardData && e.clipboardData.items) ) {
        return;
    }
});

粘贴事件提供了一个clipboardData的属性,如果该属性有items属性,那么就可以查看items中是否有图片类型的数据了。Chrome有该属性,Safari没有。

clipboardData介绍

介绍一下clipboardData对象,它实际上是一个DataTransfer类型的对象,DataTransfer 是拖动产生的一个对象,但实际上粘贴事件也是它。

clipboardData的属性介绍

属性 类型 说明
dropEffect String 默认是 none
effectAllowed String 默认是 uninitialized
files FileList 粘贴操作为空List
items DataTransferItemList 剪切板中的各项数据
types Array 剪切板中的数据类型 该属性在Safari下比较混乱
items介绍

items是一个DataTransferItemList对象,自然里面都是DataTransferItem类型的数据了。

属性

itemsDataTransferItem有两个属性kindtype

属性 说明
kind 一般为string或者file
type 具体的数据类型,例如具体是哪种类型字符串或者哪种类型的文件,即MIME-Type
方法
方法 参数 说明
getAsFile 如果kindfile,可以用该方法获取到文件
getAsString 回调函数 如果kindstring,可以用该方法获取到字符串,字符串需要用回调函数得到,回调函数的第一个参数就是剪切板中的字符串

在原型上还有一些其他方法,不过在处理剪切板操作的时候一般用不到了。

types介绍

一般types中常见的值有text/plaintext/htmlFiles

说明
text/plain 普通字符串
text/html 带有样式的html
Files 文件(例如剪切板中的数据)
简单demo
pasteEle.addEventListener("paste", function (e){
    if ( !(e.clipboardData && e.clipboardData.items) ) {
        return ;
    }

    for (var i = 0, len = e.clipboardData.items.length; i < len; i++) {
        var item = e.clipboardData.items[i];

        if (item.kind === "string") {
            item.getAsString(function (str) {
                // str 是获取到的字符串
            })
        } else if (item.kind === "file") {
            var pasteFile = item.getAsFile();
            // pasteFile就是获取到的文件
        }
    }
});

注意如果是string类型的数据,可能针对具体是text/plaintext/html进行分别的处理。

问题来了

一切看似都很顺利,如果用户粘贴了图片,通过上面的方法我们是可以获取到,可以对图片进行上传等操作了。

首先要说一下js通过剪切板能获取到的图片是怎么来的,它必须是用QQ截图或者系统截图功能截下来的图片,或者是网页上某个图片单击右键复制图片等。

但是如果用户复制MacFinder中的一个图片文件,实际上js是没有办法获取到这个图片的。但是js确实会获得一个图片类型的文件,这个图片实际上图片在电脑中的图标标识,说的比较抽象,直接上图。

如果复制的是JPEG图片,粘贴过来的却是Mac上的文件缩略图,后面依次是PNGGIFZIPDMGMac目录的文件缩略图。

很明显,这不是我们期待得到的粘贴的结果,我们期待得到文件,但实际上却得到该文件在操作系统上的缩略图。

不过粘贴事件带来的数据还有一个字符串,就是该文件的名字,所以可以用下面的方法Hack掉。

    var cbd = e.clipboardData;
    if(cbd.items && cbd.items.length === 2 && cbd.items[0].kind === "string" && cbd.items[1].kind === "file" &&
            cbd.types && cbd.types.length === 2 && cbd.types[0] === "text/plain" && cbd.types[1] === "Files"){
        return;
    }

这么多的判断条件,基本可以确定通过剪切板过来的是粘贴的文件。我刚才测试了WindowsChrome,不会有这个问题,当然也不能通过复制文件的方法得到任何文件。

问题又来了

当我打算写这篇博客的时候,Chrome开发版已经升级到了49,上面的Bug突然消失了,囧。
所以上面的Hack应该加上版本限制了。

var ua = window.navigator.userAgent;
ua.match(/Macintosh/i) && Number(ua.match(/Chrome/(d{2})/i)[1]) < 49

应该在上面的Hack再加上这两个判断,即是Mac下的Chrome49版本以下就要return

探究过程走的一点弯路

由于公司IM系统正在迁移到V2消息系统,而且现有的文件类库没有办法满足业务需求,要自己封装一个文件上传库。

然后副总找到产品经理,说新版怎么不支持Excel的粘贴,临时排期一天修复这个问题,当时是这样解决的,如果items长度是1并且是文件类型(单纯粘贴一个文件),则上传,如果items长度是4且第4个是文件类型(经过测试是Excel的粘贴结果),则上传。

当时担心由于用户各种误操作,粘贴了不该粘贴的东西,文件上传错误,用了这种白名单机制去过滤,但是万一以后有比Excel粘贴得到的数据更其他的类型,就需要多带带写代码兼容,所以,现在改成了如果判断是有Bug的情况,直接return,属于黑名单机制,这样以后再发现黑名单的情况,再添加。

可以拿来就用的代码
// demo 程序将粘贴事件绑定到 document 上
document.addEventListener("paste", function (e) {
    var cbd = e.clipboardData;
    var ua = window.navigator.userAgent;

    // 如果是 Safari 直接 return
    if ( !(e.clipboardData && e.clipboardData.items) ) {
        return;
    }
    
    // Mac平台下Chrome49版本以下 复制Finder中的文件的Bug Hack掉
    if(cbd.items && cbd.items.length === 2 && cbd.items[0].kind === "string" && cbd.items[1].kind === "file" &&
        cbd.types && cbd.types.length === 2 && cbd.types[0] === "text/plain" && cbd.types[1] === "Files" &&
        ua.match(/Macintosh/i) && Number(ua.match(/Chrome/(d{2})/i)[1]) < 49){
        return;
    }

    for(var i = 0; i < cbd.items.length; i++) {
        var item = cbd.items[i];
        if(item.kind == "file"){
            var blob = item.getAsFile();
            if (blob.size === 0) {
                return;
            }
            // blob 就是从剪切板获得的文件 可以进行上传或其他操作
        }
    }
}, false);

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/78477.html

相关文章

  • js拖拽粘贴上传与CodeMirror

    摘要:属性介绍默认是默认是在粘贴操作时为空剪切板中的各项数据剪切板中的数据类型。避免重复创建上传中文件成功失败处理已上传上传出错添加文件到队列并上传开始上传其他参考获取剪切板内容,控制图片粘贴在线代码编辑器事件说明 Markdown编辑器选用https://simplemde.com它是一款纯js实现的markdown编辑器。缺点不支持图片上传。那我们就得改造它。simplemde是基于co...

    FullStackDeveloper 评论0 收藏0
  • 前端er怎样操作剪切复制以及禁止复制+破解等

    摘要:取消默认的复制事件被复制的文字等下插入防知乎掘金复制一两个字则不添加版权信息超过一定长度的文字就添加版权信息作者链接来源掘金著作权归作者所有。以上参考资料高程操作剪贴板网页上如何实现禁止复制粘贴以及如何破解原生实现点击按钮复制文本 showImg(https://segmentfault.com/img/remote/1460000015942602?w=1280&h=720); 前言...

    mikasa 评论0 收藏0
  • 前端er怎样操作剪切复制以及禁止复制+破解等

    摘要:取消默认的复制事件被复制的文字等下插入防知乎掘金复制一两个字则不添加版权信息超过一定长度的文字就添加版权信息作者链接来源掘金著作权归作者所有。以上参考资料高程操作剪贴板网页上如何实现禁止复制粘贴以及如何破解原生实现点击按钮复制文本 showImg(https://segmentfault.com/img/remote/1460000015942602?w=1280&h=720); 前言...

    amuqiao 评论0 收藏0
  • 前端er怎样操作剪切复制以及禁止复制+破解等

    摘要:取消默认的复制事件被复制的文字等下插入防知乎掘金复制一两个字则不添加版权信息超过一定长度的文字就添加版权信息作者链接来源掘金著作权归作者所有。以上参考资料高程操作剪贴板网页上如何实现禁止复制粘贴以及如何破解原生实现点击按钮复制文本 showImg(https://segmentfault.com/img/remote/1460000015942602?w=1280&h=720); 前言...

    DevTalking 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<