<input type="file" id="naive_upload">
原理: 隐藏input原生按钮,并通过其他与其关联的标签覆盖它,从而达到相同效果,关联标签可以是label或者伪元素
<div id="new">
<input type="file" id="new_upload">
<label for="new_upload">点击上传图片显示label>
div>
使用拖拽上传的事件监听文件,需要用到的有ondragover, ondragenter, ondragleave, ondrop
<div id="drag" style="width: 200px;height: 200px;background-color: cyan;text-align: center;border:1px dashed red;">
请将文件拖拽到此区域div>
var box = document.getElementById('drag')
box.ondrop = function(ev){
box.innerHTML = '请将文件拖拽到此区域';
return false; // 阻止默认跳转事件
}
box.ondragover = function(e){
return false; //阻止默认跳转事件,并由于在里面ondragover会频繁触发,ondrop无法执行
}
box.ondragenter = function(){
box.innerHTML = '请释放鼠标';
}
box.ondragleave = function(){
box.innerHTML = '请将文件拖拽到此区域'
};
由于访问e.currentTarget.value得到的路径为带有fakepath的路径,如C:\fakepath\test.jpg,前端使用不了这个路径。
使用createObjectURL类似方法得到,不同的浏览器支持不同
// html
//
//
document.getElementById('naive_upload').onchange = function(e){
//console.log(e.currentTarget.files[0])
//console.log(e.currentTarget.value)
var url = getURL(e.currentTarget.files[0])
document.getElementById('newimage').src = url
}
//转换函数
function getURL(file) {
var url = null;
if(window.createObjcectURL != undefined) {
url = window.createOjcectURL(file);
} else if(window.URL != undefined) {
url = window.URL.createObjectURL(file);
} else if(window.webkitURL != undefined) {
url = window.webkitURL.createObjectURL(file);
}
return url;
}
FileReader对象的功能 : 读取文件内容 (异步)
readAsText() 读取文本文件,(可以使用Txt打开的文件)
readAsBinaryString(): 读取任意类型的文件,返回二进制字符串
readAsDataURL: 方法可以将读取到的文件编码成DataURL
abort: 中断读取
FileReader对象的事件:
onabort:读取文件断片时触发
onerror:读取文件错误时触发
onload:文件读取成功时触发
onloadend:文件读取完毕之后,不管成功还是失败触发
onloadstart: 开始读取文件时触发
onprogress:读取文件过程中触发
一般触发过程为onloadstart>onprogress>onload>onloadend
// 使用 监听input标签的onchange事件 或者 拖拽事件ondrop
document.getElementById('new_upload').onchange = function(e){
var reader = new FileReader();
reader.readAsDataURL(e.currentTarget.files[0],'base64');
//读取成功事件,生成的地址保存在reader.result,为blob形式
reader.onload = function(){
document.getElementById('newimage').src = reader.result
}
//读取过程事件
reader.onprogress = function(ev){
var scale = ev.loaded/ev.total;
console.log('scale=',scale)
};
}
使用multer进行处理,表单类型为multipart/form-data的数据,可自动下载到设置的目录,如果要进行其他操作,可访问其提供的req.files中的数据进行操作
<form action="http://localhost:3000/file" method="post" enctype="multipart/form-data">
<input type="file" name="file">
<input type="submit" value="form提交/file">
form>
ajax使用post上传文件存在跨域问题,可查看跨域报错信息解决
//html
//
//
// 先获取到上传的file数据
let fileData = []
document.getElementById('file_upload').onchange = function(e){
fileData = e.currentTarget.files[0]
}
// 点击上传按钮 上传到服务器
document.getElementById('button_upload').onclick = function(){
console.log('XMLHttpRequest',fileData)
var xhr = new XMLHttpRequest()
xhr.open('POST','http://localhost:3000/file')
xhr.onreadystatechange = function(){
if(xhr.readyState == 4){
console.log('finish')
}
}
//发送文件数据
xhr.send(fileData)
}
使用multer插件进行处理文件上传问题,后端可以通过req.files拿到,ajax.send需要发送序列化数据,通过new FormData建立
具体参见下方完整示例
同时拖拽多个文件
box.ondrop = function(ev){
//ev.dataTransfer.files是个数组,直接通过下标可访问
console.log(ev.dataTransfer.files)
//使用下标 如ev.dataTransfer.files[0] , ev.dataTransfer.files[1]访问
}
使用multiple属性
<input type="file" id="morefile" multiple>
//使用下标可访问
document.getElementById('morefile').onclick = function(e){
//e.currentTarget.files[0] 或者 e.target.files[0]
console.log(e.currentTarget.files)
}
//使用下标访问 e.currentTarget.files[0] , e.target.files[1]
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<style>
#new{
position: relative;
width: 150px;
height: 30px;
border-radius: 15px;
background-color: red;
text-align: center;
line-height: 30px;
}
#new:hover{
background-color: hotpink;
}
#new_upload{
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: cyan;
opacity: 0;
}
#newimage {
width: 200px;
height: 200px;
border-radius: 50%;
border: 1px solid red;
display: block;
position: absolute;
right: 400px;
top: 0;
}
#newimage2 {
width: 200px;
height: 200px;
border-radius: 50%;
border: 1px solid red;
display: block;
position: absolute;
right: 200px;
top: 0;
}
style>
head>
<body>
<h2>拖拽上传h2>
<div id="drag" style="width: 200px;height: 200px;background-color: cyan;text-align: center;border:1px dashed red;">
请将文件拖拽到此区域
div>
<img src="" alt="" id="newimage">
<img src="" alt="" id="newimage2">
<h2>去除原生样式h2>
<div id="new">
<input type="file" id="new_upload">
<label for="new_upload">点击上传label>
div>
<h2>form+post+表单上传h2>
<form action="http://localhost:3000/" method="post" enctype="multipart/x-www-form-urlencoded">
<input type="file" name="file">
<input type="text" value="hello" name="text">
<input type="text" value="world" name="text2">
<input type="submit" value="form提交表单">
form>
<h2>form+post+文件上传h2>
<form action="http://localhost:3000/file" method="post" enctype="multipart/form-data">
<input type="file" name="file">
<input type="submit" value="form提交文件">
form>
<h2>Ajax上传 需要先使用上方 <i>点击上传i> 按钮上传文件h2>
<button id="button_upload">Ajax上传button>
<h2>多文件上传> 可以选择多个文件h2>
<input type="file" id="morefile" multiple>
<h2>上方拖拽上传也可以让多个文件显示h2>
body>
<script>
// 拖拽显示图片 使用 FileReader
var box = document.getElementById('drag')
box.ondrop = function(ev){
box.innerHTML = '请将文件拖拽到此区域'
for(let i = 0; i < ev.dataTransfer.files.length; i++){
let reader = new FileReader(); //异步 使用let
//读取成功
reader.onload = function(){
console.log(i)
console.log('读取成功')
console.log(reader);
if(i==0)
document.getElementById('newimage').src = reader.result;
else
document.getElementById('newimage2').src = reader.result;
};
reader.onprogress = function(ev){
var scale = ev.loaded/ev.total;
console.log('scale=',scale)
};
reader.readAsDataURL(ev.dataTransfer.files[i],'base64');
}
return false;
}
box.ondragover = function(e){
console.log('over')
return false;
}
box.ondragenter = function(){
box.innerHTML = '请释放鼠标';
}
box.ondragleave = function(){
box.innerHTML = '请将文件拖拽到此区域'
};
// 保存上传的数据
let fileData = []
// 生成浏览器可用的url链接
function getURL(file) {
var url = null;
if(window.createObjcectURL != undefined) {
url = window.createOjcectURL(file);
} else if(window.URL != undefined) {
url = window.URL.createObjectURL(file);
} else if(window.webkitURL != undefined) {
url = window.webkitURL.createObjectURL(file);
}
return url;
}
// 新上传按钮图片显示
document.getElementById('new_upload').onchange = function(e){
var reader = new FileReader();
reader.readAsDataURL(e.currentTarget.files[0],'base64');
reader.onload = function(){
document.getElementById('newimage').src = reader.result
}
fileData = e.currentTarget.files[0]
console.log('fileData',fileData)
}
// Ajax 文件上传
document.getElementById('button_upload').onclick = function(){
console.log('XMLHttpRequest',fileData)
var xhr = new XMLHttpRequest()
xhr.open('POST','http://localhost:3000/file')
xhr.onreadystatechange = function(){
if(xhr.readyState == 4){
console.log('finish')
}
}
var form = new FormData()
form.append('file',fileData) // 在req.files看到
form.append('xd','sttring') // 在后端的req.body中可以看到
//发送文件数据
// xhr.send(fileData) //直接使用这个会导致 后端接收不到数据,req.files为空
xhr.send(form)
}
// input multiple 多文件上传显示
document.getElementById('morefile').onchange = function(e){
for(let i = 0; i < e.currentTarget.files.length; i++){
let reader = new FileReader();
reader.readAsDataURL(e.currentTarget.files[i],'base64');
reader.onload = function(){
if(i==0)
document.getElementById('newimage').src = reader.result
else
document.getElementById('newimage2').src = reader.result
}
}
}
script>
html>
后端使用的是node的express框架
使用前需要安装相应插件
npm install express -S
npm install multer -S
// npm install express -S
// npm install querystring -S
// npm install multer
var express = require('express')
var app = express()
const fs = require('fs');
const pathLib = require('path');
const multer = require('multer');
//指定上传文件保存位置
app.use(multer({dest: './upload'}).any());
// req.body为空 需要检查body-parser中间件的使用以及form标签的enctype类型值
const bodyParser = require('body-parser') // 只能用于处理application/x-www-form-urlencoded
// 文件上传 需要使用 multer 模块 用来处理 multipart/form-data
app.use(
bodyParser.urlencoded({
extended: true
})
)
app.use(bodyParser.json())
//全局设置跨域请求头
// app.all('*', function(req, res, next) {
// // res.setHeader("Access-Control-Allow-Origin", "*");
// // res.setHeader("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS");
// // res.setHeader("Access-Control-Allow-Headers", "x-requested-with,Authorization,Content-Type");
// // res.setHeader("Content-Type", "image/png");
// // console.log(res.header)
// console.log('next')
// next();
// });
app.post('/',function(req,res){
console.log('req.body=',req.body)
res.json(req.body)
})
app.options('/file',function(req,res,next){
res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS");
res.setHeader("Access-Control-Allow-Headers", "x-requested-with,Content-Type");
console.log('options /');
next();
})
app.post('/file',function(req,res){
console.log('post /file')
res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS");
res.setHeader("Access-Control-Allow-Headers", "x-requested-with,Content-Type");
// console.log('req files = ',req.files) //req.files 中保存着上传的文件数组
if (req.files){
fs.rename(req.files[0].path,req.files[0].destination+'/'+String(Math.random()).slice(3)+'.jpg',function(err){
if(err) console.log('error=',err)
else console.log('DOne')
})
res.end()
}
else{
console.log('req.files 为 undefined')
}
})
app.listen(3000,function(){
console.log('app is listening')
})