前端场景5__文件上传(前端+后端)

文章目录

      • 文件上传样式
        • 原生样式
        • 自定义样式
        • 拖拽上传
      • 上传图片同时展示图片
        • createObjectURL
        • FileReader方法
      • 文件上传到服务器
        • form标签
        • Ajax + Post
        • 后端
      • 多文件上传
        • 拖拽上传
        • input标签上传
      • 完整示例
        • 前端
        • 后端

文件上传样式


原生样式
<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

使用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方法
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标签

<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

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]访问
}
input标签上传

使用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')
})

你可能感兴趣的:(前端,后端,前端,后端,javascript)