2020-04-01

我们都知道,html5中有个input type=file元素。用该元素可以实现页面上传文件的功能

但一般的做法只是简单的在表单中操作,我来研究一下深层东西

想要了解它,就要知道它的内置对象,files

页面上写一个input,然后选俩个图片,打印这个input对象

("input[name='file1']").change( function(e){ console.log(("input[name='file1']"))
})
发现有下列值,在0中,有一个files对象

我们发现input选择的文件被记录到了这个对象中,这个是fileList对象,是一个只读对象,不能修改

因为它不能修改,所以很难实现对已选中多个文件的删除某个文件等操作

里面记录了文件的name,size,type,和修改时间等,可知这个对象只存放了一些文件的信息,相当于是本地文件的索引,并不是把文件放到input中了,上传文件时它会再去找到实际的本地文件

fileList数组包含多个File对象,File对象是继承与Blob对象的,关于file,url,blob,dataUrl可以详细查查

一般url可以是本地地址,http地址等

blob对象一般的形式是:blob:http://192.168.100.151:8080/1148dcd6-952e-4478-823d-21b37e537c2f,属于浏览器对象

dataUrl 一直格式是:以data:image/jpeg;base64,这种类似形式打头的一串很长的字符串。

这三种形式在img标签中src属性都可以调用。

File对象有name,size,lastModified属性

File对象的创建:

var file1=new File([blob], "aa.png",{type:"image/jpg"}); //第一个参数是Blob对象或者dataUrl,第二个参数是文件名,三个参数可选,规定文件类型

注意:第一个参数必须是对象,不能是转换成的字符串,比如uniapp或者微信小程序的chooseImage方法返回的blob的url,他是一个字符串,这样生成的File对象只是将url字符串变成文件了,不是文件本身!!!

想把blob字符串变成Blob对象,可以用es6的:const blob = await fetch(image.path).then(r => r.blob())

或者用传统的XHR或者ajax也行,就是把blob对象根据url给获取出来就行。

利用这个files对象,我们可以实现很多功能,例如:

一.选择图片未经后端显示预览图片

方法1:利用window的url工具将文件生成url,再将url赋值给img的src属性,显示出选中图像

顺便提一下,input中控制选中类型加一个accept属性就行了,只会显示设定的文件类型

<input id="file1" type="file" name="file1" multiple="multiple" accept=".doc,.jpg">
('.fbpj-camera').change(function(event) { //('.dianpuzhuangxiu .addmokuai .block .shuoming1 .pic .pic1').children().remove();
// 根据这个 <input> 获取文件的 HTML5 js 对象
var files = event.target.files, file;
if (files && files.length > 0) {
// 获取目前上传的文件
file = files[0];
// 来在控制台看看到底这个对象是什么
console.log(file);
// 那么我们可以做一下诸如文件大小校验的动作
if(file.size > 1024 * 1024 * 2) {
alert('图片大小不能超过 2MB!');
return false;
}
// !!!!!!
// 下面是关键的关键,通过这个 file 对象生成一个可用的图像 URL
// 获取 window 的 URL 工具
var URL = window.URL || window.webkitURL;
// 通过 file 生成目标 url
var imgURL = URL.createObjectURL(file);
// 用这个 URL 产生一个 <img> 将其显示出来
$('.fbpj .container').prev().find("img").attr('src', imgURL);
// 使用下面这句可以在内存中释放对此 url 的伺服,跑了之后那个 URL 就无效了
//URL.revokeObjectURL(imgURL);
}
});
方法二:利用html5的FileReader()读取文件

*前提是浏览器支持的话

if(window.FileReader) {
var fr = new FileReader();
// add your code here
}
else {
alert("Not supported by your browser!");
}
<script type="text/javascript">
function showPreview(source) {
var file = source.files[0];
if(window.FileReader) {
var fr = new FileReader();
fr.onloadend = function(e) {
document.getElementById("portrait").src = e.target.result;
};
fr.readAsDataURL(file); //也是利用将图片作为url读出
}
}
</script>

<input type="file" name="file" οnchange="showPreview(this)" />
<img id="portrait" src="" width="70" height="75">
FileReader还有一些其他用法

<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta name="author" content="oscar999">
<title></title>
<script>
function handleFiles(files)
{
if(files.length)
{
var file = files[0];
var reader = new FileReader();
reader.onload = function()
{
document.getElementById("filecontent").innerHTML = this.result;
};
reader.readAsText(file); //作为字符串读出
//reader.readAsText(file,'gb2312'); //默认是用utf-8格式输出的,想指定输出格式就再添加一个参数,像txt的ANSI格式只能用国标才能显示出来
}
}
</script>

</head>
<body>

<input type="file" id="file" οnchange="handleFiles(this.files)"/>
<div id="filecontent"></div>
</body>
</html>
readAsText一般只能读取txt,html等等文件,局限性较大,比如想要前端读excel文件,由于解决文件编码问题较为复杂,需要用到js-xlsx插件,具体可百度方法。

常用API:

FileReader.readAsDataURL(File) //转换成base64格式

FileReader.readAsText() //转换成字符串格式

FileReader.readAsArrayBuffer(File) //转换成ArrayBuffer格式

FileReader.readAsBinaryString(File) //转换成原始二进制格式(貌似已被废除)

FileReader.onload = function (e) { console.log(e.target.result) } //在上述读取事件完成时触发

二.文件拖拽的方法保存文件

关于文件拖拽下面有注释,我主要说一下怎么给用js给input赋值,而不是手动去选文件

因为拖拽的区域只是一个div,无法进行上传操作,所以需要加一个form和input,让拖拽进去的文件进入input中。

取出files后,用$("#file1")[0].files=files;将文件赋值给input,注意赋值的必须是fileList对象,不要试图只放进去一个文件,fileList只读。

然后用h5中的FormData将form转化,提交即可

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<style>
.container{
width:300px;height: 300px;
border:2px dashed #ddd;
text-align: center;
padding:50px;
}
</style>
<title>
培训活动列表
</title>
</head>
<body>
<div class="container">
拖拽进入
</div>
<form id="form1" method="post" enctype="multipart/form-data">
<input type="file" name="file1" id="file1" value="" />
</form>
<script type="text/javascript">
('.container').bind('dragenter dragover', ignoreDrag);(".container").on({drop:function(e){
var flag=true;
e.preventDefault();
//jquery的file要去e.originalEvent里面拿,拖拽获取files的方式与input的不同
var files = e.originalEvent.dataTransfer.files;
//var files = e.dataTransfer.files; 原生的话这样就可以获取
for(var i=0;i<files.length;i++){
myFileReader(files[i],function(result,file){
if(result){
//文件
console.log(file.name)

            }else{
                //文件夹
                console.log("不要上传文件夹")
                flag=false;
            }
        });
    }
    if(flag){
        $("#file1")[0].files=files;   //关键:将取到的文件赋值给input,用于ajax提交文件!!!
        var formData = new FormData($("#form1")[0]);     
        $.ajax({
            url : "/it/orderManage/saveActivity",
            type : 'POST',
            data : formData,
            // 告诉jQuery不要去处理发送的数据
            processData : false,
            // 告诉jQuery不要去设置Content-Type请求头
            contentType : false,
            async : true,
            success : function(ret) {
                //alert("上传成功")
                if(ret){
                    $("#trainInfoModal").modal("hide");
                    layer.alert("保存成功")
                    $('#orderTable').bootstrapTable("refresh");
                    $("#trainInfoModal input").val("");
                    $("#trainInfoModal textarea").val("");

                }
            }
        });
    }
    console.log(files);
}})

function ignoreDrag(e) {e.originalEvent.stopPropagation();
    e.originalEvent.preventDefault();
}

function myFileReader(file, callback){
    if(!window.FileReader){
        callback(true,file);
        return false;
    }
    var fr = new FileReader();
    fr.readAsDataURL(file);
    fr.οnlοad=function(e){
        callback(true,file);
    }
    fr.οnerrοr=function(e){  //不好判断是否是文件夹,通过上传报错可以判断是文件夹
        callback(false,file);
    }
    return true;
};

</script>
</body>
</html>
后台获取文件还是用MutipartFile[]接收

public String saveActivity(@RequestParam HashMap<String, String> param,
//@RequestParam(value = "banner") MultipartFile[] files,
@RequestParam(value = "file1") MultipartFile[] file1,
HttpServletRequest request,
String fileNames,
String TID, HttpServletRequest req) {

三.vue+axios 上传文件
无论ajax还是axios,都不是直接用表单提交的,都是 要用 new FormData()转化一下。

所以axios方法与ajax方法类似

<input type="file" class="inputBtn" @change="uploadMarketingForm">
uploadMarketingForm(e){
console.log(e)
var fileName=e.target.files[0].name; //文件名
var fileSize=e.target.files[0].size; //文件大小
var param = new FormData();
//添加表单参数,如果后台用文件数组接收
//param.append("file", e.target.files);
//如果后台只接收单一文件
param.append("file", e.target.files[0]);
//设置表头类型
const config = {
headers: { "Content-Type": "multipart/form-data" }
};
this.axios.post("/.../uploadTest", param, config).then(res => {
console.log(res);
});
},
在java spring mvc中还是这么接收

@ResponseBody
@RequestMapping(value = "uploadTest", produces = "text/plain;charset=UTF-8")
public String uploadTest(@RequestParam Map<String,String> param,@RequestParam(value = "file") MultipartFile[] file1,
HttpServletRequest request) throws IOException {
RetBase retBase = new RetBase();
//文件可以在参数中用MultipartFile[](多文件) 或者 MultipartFile (单一文件)接收
//也可以像这样在request中接收
MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
MultipartFile multifile = multipartRequest.getFile("file"); // 通过参数名获取指定文件
String fileName = multifile.getOriginalFilename();
// 获取文件后缀
String prefix=fileName.substring(fileName.lastIndexOf("."));
// 用uuid作为文件名,防止生成的临时文件重复
final File file = File.createTempFile(UUID.randomUUID().toString(), prefix);
// MultipartFile to File
return JSON.toJSONString(retBase, SerializerFeature.WriteMapNullValue);

————————————————
版权声明:本文为CSDN博主「lianzhang861」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/lianzhang861/java/article/details/80283120

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,830评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,992评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,875评论 0 331
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,837评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,734评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,091评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,550评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,217评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,368评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,298评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,350评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,027评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,623评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,706评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,940评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,349评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,936评论 2 341

推荐阅读更多精彩内容

  • Android 零基础入门 Android 零基础与进阶知识学习 Roadmap 概述 本文适用于: 零基础,想学...
    王岩_shang阅读 336评论 0 1
  • 2.1、方法的重载:overload 概念:一个类中的,一个功能方法的多种体现形式(有不同的方法体)。 举例: ...
    机会留给有准备的人阅读 215评论 0 0
  • 一、 语法 .innerHTML =? :写入到页面; document.getElementById(“...
    执着_7fb1阅读 98评论 0 0
  • 今天在shell脚本用到var截取文件名,感觉挺实用的,所以抄了一下稍微比较全面的的笔记,之后会继续补充,下面是工...
    烂笔头2020阅读 402评论 0 2
  • “ 作为一名土生土长的夏邑人,我对自己的家乡和方言却知之甚少。而‘言续’给我机会去深入了解它。它在地图上或许只是一...
    北京的京阅读 407评论 0 0