在图形界面的操作系统中,拖拽操作应该是一个比较常见的功能。比如 对于不太懂电脑的小白来说最简单的删除文件的方式就是把文件拖到桌面上的回收站图标,打开文件也是直接拖到相应的软件中。拖拽操作可以说是最便于小白理解的一种操作方式。

拖拽文件上传

目前大多数的网络相册和网盘都支持直接拖拽文件上传,例如,百度网盘、Google 云端硬盘、Google 相册 等,都支持拖拽文件上传。不过要使用拖拽文件上传浏览器必须要能很好的支持 HTML5,也就是说那些老 IE 都是用不了的。

这里先放一个 div 来接收文件:

<div>把文件拖到此处上传</div>

div 加一些 CSS 方便查看:

div{
    width: 300px;
    height: 300px;
    background: #00e080;
    color: #ffffff;
    font-size: 20px;
    text-align: center;
    line-height: 300px;
}

效果如下:

拖拽文件截图

我这里只是为了方便演示,在实际的开发中接收文件的范围可以大一些,下面是 JS:

var Div = document.querySelector('div');  //  获取div

//  文件进入div
Div.ondragenter = function(event) {
    //  阻止浏览器默认事件
    event.preventDefault();
    event.stopPropagation();
};

//  文件在div上,但是还未松开鼠标
Div.ondragover = function(event) {
    //  阻止浏览器默认事件
    event.preventDefault();
    event.stopPropagation();
};

//  文件进入Div并且已经松开鼠标
Div.ondrop = function(event) {
    //  阻止浏览器默认事件
    event.preventDefault();
    event.stopPropagation();

    //  把文件传入files变量,有的浏览器需要通过event获取
    var files = this.files || event.dataTransfer.files;

    //  新建FormData对象
    var formData = new FormData();
    //  封装一个formData
    formData.append('files', files[0]);

    // 新建XMLHttpRequest对象
    var xhr = new XMLHttpRequest();
    //  设置提交方式 url 是否异步
    xhr.open('post', 'server.php', true);
    //  设置请求头
    xhr.setRequestHeader('X-Request-With', 'XMLHttpRequest');
    //  提交数据,传入已封装的FormData
    xhr.send(formData);

    //  此方法在成功提交并接收到数据的时候触发
    xhr.onreadystatechange = function () {
        //  验证一下是否全部接收完成
        if (xhr.readyState == 4) {
            //  在控制台输出接收到的数据
            console.log(xhr.responseText);
        }
    }
};

这里因为有注释和空行,所以看起来内容很多,实际上很简单,下面是详细说明:

dragenter 事件

被拖动的内容进入目标元素时触发,上面的文件如果拖入到div就会触发,在不放开鼠标的情况下也会触发,event.preventDefault() 主要是禁止浏览器的默认事件,有的浏览器文件拖入以后可能会直接读取文件,详细的 preventDefault 说明可以访问: https://developer.mozilla.org/zh-CN/docs/Web/API/Event/preventDefaultevent.stopPropagation() 主要是阻止冒泡,详细的可以看: https://developer.mozilla.org/zh-CN/docs/Web/API/Event/stopPropagation

dragover 事件

被拖动的内容在目标元素上时触发,而且是连续触发,上面 的文件拖入 div 内只要不离开就会连续触发。

drop 事件

被拖动的内容进入目标元素并且已经放开鼠标时触发,上面的文件进入 div 放开鼠标后触发,如果文件移出 div 放开鼠标也不会触发。

this.files 属性

获取拖入的文件列表,一般用于input这一类的元素。

event.dataTransfer.files 属性

获取拖入的文件列表,一般用于div这一类和文件无关的元素。

event.originalEvent.dataTransfer.files 属性

一般用于j Query 获取文件列表,这里没有用到。

上面的两种方式都是获取拖入的文件列表,文件拖入后会返回一个包含文件列表的数组,数组的长度取决于文件数量。我上面上传的是第一个文件。文件列表中的文件又包含一些属性,下面是详细说明:

属性类型读/写说明
lastModifiedNumber只读文件最后修改时间,1970年1月1日到现在的时间戳。
lastModifiedDateobject只读文件的最后修改日期。
namestring只读文件名,不包含路径。
typestring只读文件类型,如 image/png 。
sizeNumber只读文件大小(字节)。

以上面的 files 数组为例,我想获取第一个文件的大小,代码如下:

files[0].size

到这里拖拽的部分就算是写完了,关于 FormDataXMLHttpRequest 可以看下面两篇文章:

这里获取的 files 文件对象和文件表单的 files 对象是一样的。

预览本地图片

在用户上传头像或各种图片背景时可以在正式上传之前就加载图片让用户预览,满意在上传,避免用户多次更换头像造成服务器带宽和空间的浪费。

这里用的是文件表单选择文件,用拖拽的方式也可以实现,主要还是需要 files 对象,下面是 HTML:

<input type="file">
<img src="" alt="图片">

设置一下 img 的宽度和高度,方便演示:

img{
    width: 640px;
    height: 360px;
    background: #f0f0f0;
    border: 1px solid #0063b1;
    display: block;
}

效果如下:

img

在实际开发中可以隐藏文件表单,用按钮调用文件表单来选择文件。

下面是 JS 代码:

var Img = document.querySelector('img');  //  获取img
var fileInput = document.querySelector('input');  //  获取文件表单

//  文件表单的内容改变,也就是选择完文件触发
fileInput.onchange = function() {
    //  如果未选择任何文件
    if (fileInput.value == '') {
        return false;
    }

    //  创建FileReader对象
    var reader = new FileReader();

    //  读取文件
    reader.readAsDataURL(fileInput.files[0]);

    //  读取文件完成时触发
    reader.onload = function (event) {
        //  设置img的src
        Img.src = event.target.result;
    };
};

最终效果如下:

图片预览

下面是详细说明:

change 事件

在域的内容改变时触发,例如 input 的内容改变就会触发,选择完文件后文件表单的 value 会变为选择的文件的文件名,如果选择了多个文件也只会显示第一个文件的文件名。

FileReader 对象

FileReader 对象允许 Web 应用程序异步读取存储在用户计算机上的文件(或原始数据缓冲区)的内容,使用 FileBlob 对象指定要读取的文件或数据。

readAsDataURL() 方法

readAsDataURL 方法会读取指定的 BlobFile 对象。读取操作完成的时候,readyState 会变成已完成 DONE,并触发 loadend 事件,同时 result 属性将包含一个data:URL格式的字符串(base64编码)以表示所读取文件的内容。

FileReader.onload 事件

FileReaderonload 事件会在文件读取完成时触发。

下面是 FileReader 的一些事件说明:

事件说明
FileReader.onabort处理abort事件。该事件在读取操作被中断时触发。
FileReader.onerror处理error事件。该事件在读取操作发生错误时触发。
FileReader.onload处理load事件。该事件在读取操作完成时触发。
FileReader.onloadstart处理loadstart事件。该事件在读取操作开始时触发。
FileReader.onloadend处理loadend事件。该事件在读取操作结束时(要么成功,要么失败)触发。
FileReader.onprogress处理progress事件。该事件在读取Blob时触发。

event.target.result 属性

readAsDataURL 读取文件完成后会返回一个URL,把 imgsrc 设置为 readAsDataURL 返回的图片URL就能显示图片了。

以上就是 JavaScript 拖拽文件上传和预览本地图片的方法,无论是拖拽上传还是预览本地图片都需要浏览器支持 HTML5。

相关参考文章: