JS如何实现剪切板图片粘贴直接上传?

Web前端 潘老师 10个月前 (01-31) 519 ℃ (0) 扫码查看

在H5技术发展如火如荼的今天,前端再也不是页面和切图仔的代名词,而今的前端早已不再是写写页面撸撸简单交互了,而今的前端相比十年前已经发生了翻天覆地的变化,像近几年出现的angularjs,vuejs,react等等前端框架已被广泛应用于各类在线协作平台、webapp中,以node为技术栈的各类平台已经广泛被很多大公司推出,前端已经变天了。

在之前对于图片上传最原始的做法就是通过在form表单中放置type为file的input标签,然后由用户选择后提交上传,但是页面在提交的时候会刷新,这种用户体验非常不友好,后来出现了XMLHttpRequest,借助xhr我们可以在不刷新页面的情况下直接上传图片,用户体验有了较大的提升,但是还想再z做进一步优化,接着出现了dataTransfer和formData,我们发现可以通过借助dataTransfer和formData实现从电脑的资源管理器直接拖拽图片到网页上传,具体过程是从电脑拖拽图片到网页,js在drop的事件中取到当前事件对象的dataTransfer进而得到文件对象,然后实例化formData对象,借助xhr异步上传图片,这无疑是一个锦上添花的功能,至此,对于上传的用户体验已经达到了一定的高度,那么我们是不是就不能再进一步,玩点更高逼格的东西,让用户体验再上一个台阶呢?

如果你也想更好的学习JavaScript,不妨入手一本JavaScript红宝书

JavaScript高级程序设计 第4版(图灵出品) JavaScript高级程序设计 第4版(图灵出品)
web前端开发教程,JS”红宝书”升级,入门+实战,涵盖ECMAScript2019,提供教学视频+配套编程环境,可直接在线运行随书代码 

对于用惯了word、excel等桌面端软件的用户来说,简单的复制粘贴就能将需要的图片插入到需要的位置无疑是最方便的,那么我们是不是也可以在浏览器端实现这个功能呢?

要实现该功能,我们就需要先从剪切板中获取到图片,还好浏览器为我们提供了相关支持,代码如下:


document.addEventListener('paste', function(event) {
    const items = event.clipboardData ? event.clipboardData.items : [];
    let file = null;
    
    if (items && items.length) {
        for (var i = 0; i < items.length; i++) {
            if (items[i].type.indexOf('image') !== -1) {
                file = items[i].getAsFile();
                break;
            }
        }
    }
});

需要注意的是,不要用数组的find方法去查找图片对象,因为items是一个伪数组,并没有find方法。

在以上代码中,我们全局监听document对象上的paste事件,当粘贴事件触发时遍历剪切版对象(clipboardData)中的所有items,找到类型为图片的item并调用getAsFile方法得到文件对象,拿到file 对象后我们有两种选择:

1、通过fileReader得到文件对象的base64字符串,代码如下:

const reader = new FileReader();
reader.onload = function(e){
  // 通过e.target.result取到base64然后上传
  // 作为src设到image标签上进行预览
}
reader.readAsDataURL(file); //此处的file为上面得到的文件对象

在得到了图片的base64字符串后我们可以将其传递给后端,后端接受base64数据并存储,如果我们需要在上传前或者上传过程中预览图片,可以直接将上面得到的base64数据作为src传递给image标签然后预览。

2、通过formData将文件对象转换为文件流数据,代码如下:

const formData = new FormData();
formData.append('file', file);

相比base64字符串的庞大,文件流上传会是一个更优的选择,所以这里选用formData来上传文件,代码如下:

const xhr = new XMLHttpRequest();
xhr.onload = function () {
    try {
        // 取得响应消息
        const result = JSON.parse(this.responseText);
    } catch(err) {
        console.log(err)
    }
};
xhr.open('POST', './upload_file.php', true);
xhr.send(formData);

当然上述代码只是传递了图片文件对象,如果除了文件外还需要传递其他自定义内容比如文件名,时间之类的,只需要通过formData对象的append方法添加其他字段即可。

对于后端文件保存的实现方式多种多样,不同人有不同的选择,不管用node、php还是java只要用的顺手都是可以的,这里简单介绍一下php的实现,代码如下:


<?php
  $allows = array("png", "jpg");
  $filepath = 'upload/';

  $imgname = $_FILES['file']['name'];
  $tmp = $_FILES['file']['tmp_name'];
  $extension = getExtension($imgname);
  $destpath = $filepath . 'image.' . $extension;

  function getExtension($filename) {
    return pathinfo($filename, PATHINFO_EXTENSION);
  }

  if (in_array($extension, $allows)) {
    move_uploaded_file($tmp,  $destpath);
    echo json_encode(array("path" =>  $destpath, "ret" => 0));
  } else {
    echo json_encode(array("ret" => -1));
  }
?>

如果你需要查看在线的demo,可以访问:http://demo.deanhan.cn/paste-upload/

当然上面的实现还是存在一定的局限性,对于qq、微信等软件的截图和快捷键print screen等方式得到的截图以及任意网页的右击复制图片都能完美支持,但是,对于电脑本地图片文件的复制没办法从剪切版直接获取到,如果有哪位朋友有解决的方案请一定不吝赐教。

该实现方式在chrome和safari上测试完美支持,但对于safari浏览器使用方式略有差别,只能在设置了contenteditable属性的元素身上才能触发,要是遇到了IE就直接放弃吧,就仨字“不支持”,溜了溜了,多的就不说了,说多了都是泪 。


版权声明:本站文章,如无说明,均为本站原创,转载请注明文章来源。如有侵权,请联系博主删除。
本文链接:https://www.panziye.com/java/web/5809.html
喜欢 (0)
请潘老师喝杯Coffee吧!】
分享 (0)
用户头像
发表我的评论
取消评论
表情 贴图 签到 代码

Hi,您需要填写昵称和邮箱!

  • 昵称【必填】
  • 邮箱【必填】
  • 网址【可选】