微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

JS实现表单多文件上传样式美化支持选中文件后删除相关项

开发中会经常涉及到文件上传的需求,根据业务不同的需求,有不同的文件上传情况。

有简单的单文件上传,有多文件上传,因浏览器原生的文件上传样式及功能支持度不算太高,很多时候我们会对样式进行美化,对功能进行完善。

本文根据一个例子,对多文件上传样式做了一些简单的美化(其实也没怎么美化。。),同时支持选择文件自定义删除相关的文件,最后再上传

文章篇幅较长,先简单看看图示:

一、文件上传基础

1. 单文件上传

最简单的文件上传,是单文件上传,form标签中加入enctype="multipart/form-data",form表单中有一个input[type="file"]项

rush:js;">
PHP" enctype="multipart/form-data">

2. 多文件上传

  1)类似单文件上传,简单的多文件上传其实就是多几个input[type="file"]项

rush:js;"> PHP" enctype="multipart/form-data">

  2) HTML5为表单文件项新增了一个multiple属性,可以设置实现选择多个文件,如

PHP" enctype="multipart/form-data">

二、表单文件上传的美化

看了上面几个图片,可以知道原生的文件选择项样式是最基本的,主要体现在三个点:

无边框,与其他有边框的元素不合拍 选择文件的按钮样式太基础 选择多个文件后只显示总数,未显示详细选择的文件名 基于几个问题,可以按需对其进行美化

第一点可以直接添加边框的样式

第二点需要增添其他元素,可以新增一个按钮(自行按需美化),将原始文件框隐藏,用JS事件绑定,点击按钮后模拟文件框的点击

rush:js;"> display: none;"> 文件" onclick="document.getElementById('userImage').click()">

第三点与第二点类似,也得添加新的元素,选择文件后,通过JS获取选择的文件信息,并在新的元素中显示出来

想着很简单,但随之而来的问题就是,如果选中的文件数量很多,新元素占空间的多少就是个问题,可以显示几个文件,再通过“查看更多文件”查看到更多的信息

随之另外的想法是,一次性选中的文件很多,想取消某个文件时,又得重新选择。这未免太繁琐,所以需要提供即时删除某个选中文件的操作

三、选中文件后的删除

要提供选中文件后可删除的操作,就必然需要提供相关入口及脚本操作,下面围绕这点来做些解析

1. 界面的处理

选择文件后,我们可以通过删除按钮删除选中的文件,因为会出现多文件的情况,所以需要一个信息模版

rush:js;">

选中的文件一多,就得再增添一个下拉框做辅助,最多显示5个文件信息,然后通过下拉按钮展开下拉框(按钮样式自行设定)

这里5个文件间的位置计算的不是很到位,主要是这段代码,可以自行设定

rush:js;"> // 计算每一项坐标left、占宽width left = i === 0 ? 2 : 2 + i * (100 / fileTempLen); width = 100 / fileTempLen - 2;

下拉列表里面的每一项也是一个模版

rush:js;">   

以下为初始的HTML结构

rush:js;">  PHP" enctype="multipart/form-data">

以下为全部CSS样式

rush:js;"> display: inline-block; border: 1px solid #ccc; border-radius: 3px; } .file-temp { position: relative; display: none; width: 300px; height: 31px; } .file-temp-item { position: absolute; top: 4px; height: 24px; } .item-more-btn { display: inline-block; position: absolute; top: 18px; right: 0.5%; width: 10px; height: 10px; color: #777; cursor: pointer; } .item-more-btn:hover { border-top-color: #aaa; } .file-temp-name { display: inline-block; overflow: hidden; width: 90%; height: 26px; padding: 2px 15px 2px 5px; border-radius: 2px; background-color: #eaeaf3; text-overflow: ellipsis; white-space: Nowrap; } .file-temp-btn { position: absolute; display: inline-block; top: 4px; right: 11%; width: 18px; height: 18px; line-height: 18px; text-align: center; border: 1px solid #ddd; background-color: #ccc; border-radius: 50%; color: #fff; font-size: 18px; cursor: pointer; } .item-more { position: absolute; overflow-y: auto; display: none; padding-left: 0; width: 300px; max-height: 150px; list-style: none; } .item-more li { position: relative; padding: 5px; border: 1px solid #ccc; border-top: none; } .item-more li:hover { background-color: #f5f5f9; } .file-item-more-name { display: inline-block; width: 90%; overflow: hidden; text-overflow: ellipsis; white-space: Nowrap; } .file-item-more-btn { position: absolute; display: inline-block; top: 8px; right: 2%; width: 18px; height: 18px; line-height: 18px; text-align: center; border: 1px solid #ddd; background-color: #ddd; border-radius: 50%; color: #fff; font-size: 18px; cursor: pointer; } .file-item-more-btn:hover { background-color: #ccc; } .upload-tip { display: none; margin: 50px auto; text-align: center; font-size: 12px; }

2. 脚本的处理

下面,着重介绍JS脚本的处理

获取到选中文件的信息,自然想到用value属性,但通过文件项的value只能获取一个文件路径(第一个),无论有没有multiple

无multiple

rush:js;">

有multiple

rush:js;">

既然直接通过value获取不到所有选中的文件信息,只能寻求其他途径。

  1)FileList

获取选中的文件信息,还可以用FileList对象,这是在HTML5中新增的,每个表单文件项都有个files属性,里边存储这选中的文件的一些信息

rush:js;">

选中两个文件后,查看文件信息

FileList对象看起来是个类数组,有length属性。所以我们应该可以通过修改删除相关的项来自定义我们选择的文件(注意其实这是不能修改的,且继续看下去)

假如我选择了两个文件,想删除第二项目,使用splice删除,则

rush:js;">

报错,由此可知FileList的length属性是只读的,那直接修改为可写可配置呢

rush:js;"> Object.defineProperty(FileList.prototype,'length',{ writable: true,configurable: true });

配置之后length能修改了,乍一看还以为splice生效了,然而输出一看,FileList对象内容不变,仍为两项

查阅了一些资料后,了解到浏览器为了安全性的考虑,把FileList对象的内容设为了不可更改,只可以手动置空,但不能修改内容

所以,解决办法是,新增一个数组,初始复制FileList对象的文件内容,之后的修改操作则通过这个可更改的数组进行

rush:js;"> // 存储更新所选文件 var curFiles = []; ... // 选中文件后 var files = this.files; if (files && files.length) { // 原始FileList对象不可更改,所以将其赋予curFiles提供接下来的修改 Array.prototype.push.apply(curFiles,files); }

假如点击了删除叉叉,可以直接更新文件信息数组

rush:js;"> var name = $(this).prev().text(); // 去除文件 curFiles = curFiles.filter(function(file) { return file.name !== name; });

这样一来,更新文件信息的问题得到解决,然后就可以进行文件上传

点击文件上传,如果直接调用$form.submit(); 则上传文件信息依然是初始的FileList对象,达不到我们自定义的要求,所以需要用Ajax提交

那么,该怎么想后台提供一个文件对象呢?

  2)FormData

HTML5引入了表单的新对象FormData,它可以生成一个表单对象,我们可以向其中获取/设置键值对信息,再一并提交给后台

引用MDN的FormData使用方法,我们可以添加各种类型的数据,使用ajax提交

rush:js;"> var oMyForm = new FormData(); oMyForm.append("username","Groucho"); oMyForm.append("accountnum",123456); // 数字123456被立即转换成字符串"123456" // fileInputElement中已经包含了用户所选择的文件 oMyForm.append("userfile",fileInputElement.files[0]); var oFileBody = ''; // Blob对象包含的文件内容 var oBlob = new Blob([oFileBody],{ type: "text/xml"}); oMyForm.append("webmasterfile",oBlob); var oReq = new XMLHttpRequest(); oReq.open("POST","http://foo.com/submitform.PHP"); oReq.send(oMyForm);

也可使用JQ的封装的ajax,不过要注意设置processData和contentType属性为false,防止JQ胡乱解析文件格式

rush:js;"> var fd = new FormData(document.getElementById("fileinfo")); // 使用某个表单作为初始项 fd.append("CustomField","This is some extra data"); $.ajax({ url: "stash.PHP",type: "POST",data: fd,processData: false,// 告诉jQuery不要去处理发送的数据 contentType: false // 告诉jQuery不要去设置Content-Type请求头 });

这里有几个要注意的点:

1)FormData中的属性值接受的是单个文件信息,不能是复合性的对象。可能表意不明,且看

rush:js;"> var fd = new FormData($('#form')[0]); fd.append('myFileTest',curFiles); $files = $_REQUEST['myFileTest']; var_dump($files);

PHP接收传过来的数据,数据却被直接转换成字符串了,非文件对象

curFiles是文件对象,那PHP端是不是应该用$_FILES来接收信息呢,试试换成$files = $_FILES['myFileTest'];

直接出问题了,说明不能这样处理,需要将curFiles内容一项一项拆开,即单个文件信息

rush:js;"> var fd = new FormData($('#form')[0]); for (var i = 0,j = curFiles.length; i < j; ++i) { fd.append('myFileTest[]',curFiles[i]); } $files = $_FILES['myFileTest']; var_dump($files);

文件接收成功,接下来就可以按需进行文件的操作了

2)后端获取文件信息的时候,是直接通过原始$_FILES获取的,其他一般的信息才用$_REQUEST获取

换成$files = $_REQUEST['myFileTest'];试试,直接就是出现找不到myFileTest的问题

试试添加一般的文件再提交

rush:js;"> var fd = new FormData($('#form')[0]); for (var i = 0,curFiles[i]); } fd.append('myTest',[1,2,3]); $files = $_FILES['myFileTest']; $test = $_REQUEST['myTest']; var_dump($test); var_dump($files);

3)如果需要multiple的多文件上传,则需要在文件项的文件添加[]号,表示这是一个文件的数组,以供后端处理解析

rush:js;"> fd.append('myFileTest[]',curFiles[i]);

如果没有后面的[],则连续的append会直接覆盖原来的,最后后端获取到的只是最后append进去的项

4)不要直接在JQ的ajax中实例化出一个FormData对象,会出问题

直接在data属性生成FormData对象,会被JQ忽略,所以后端什么信息也拿不到

混合表单项简单的例子:

在表单处理中,很多时候我们会进行文件上传和其他基础项的提交,简单地多加一个input项目,看看是否处理成功

rush:js;">

rush:PHP;"> count($files['name']),'num' => $test )); ?>

以下为全部的JS脚本:

rush:js;">

以上所述是小编给大家介绍的JS实现表单多文件上传样式美化支持选中文件删除相关项。编程之家 jb51.cc 收集整理的教程希望能对你有所帮助,如果觉得编程之家不错,可分享给好友!感谢支持

原文地址:https://www.jb51.cc/js/45450.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐