下面要做一个ajax上传文件显示进度的操作: 
1102860-20180817120206270-1407048366.png
这里先上代码:

1、前端代码

upload.html

<!DOCTYPE html><html lang="en"><head>  <  charset="UTF-8">  <  name="viewport" content="width=device-width, initial-scale=1.0">  <  http-equiv="X-UA-Compatible" content="ie=edge">  < >Document</ >  <  href="https://cdn.bootcss.com/bootstrap/4.0.0/css/bootstrap.css" rel="stylesheet">  <style>    .progress-area {      padding: 20px;    }  </style></head><body>  <div class="">    <p>文件上传</p>    <div>      <input type="file" name="file" id="file" />      <div class="img-preview">          <p>图片预览(如果上传文件时图片)</p>          <img id="image" src="" width="200" />      </div>      <button id="upload">上传</button>      <button id="btn">终止上传</button>      <div class="progress-area">        进度        <div class="progress">          <div class="progress-bar" id="progress" role="progressbar"  aria-valuenow="25" aria-valuemin="0" aria-valuemax="100">0%</div>        </div>      </div>    </div>  </div>  < >    (function () {        'use strict';        var file = document.querySelector('#file');        var upload = document.querySelector('#upload');        var progress = document.querySelector('#progress');        var image = document.querySelector('#image');        var xhr = new  HttpRequest();        var loaded = 0;        var total = 0;        upload.addEventListener('click', uploadFile, false);        file.addEventListener('change', previewImage, false);        // 点击上传        function uploadFile(event) {          if(!file.files[0]) {            alert('请选择文件')            return          }          var formData = new FormData();           // 利用这个来提交xhr,具体的可看下面的mdn 介绍           // https://developer.mozilla.org/zh-CN/docs/Web/API/FormData/Using_FormData_ s          formData.append('test-upload', file.files[0]);           // 将input 选择出来的文件调用append()方法来添加字段          xhr.  = uploadSuccess;           // 上传方法          xhr.upload.onprogress = setProgress;          // 上传过程方法          xhr.open('post', '/upload', true);          // 打开请求方式和接口          xhr.send(formData);          // 发送数据        }        // 成功上传        function uploadSuccess(event) {          if (xhr.readyState === 4 && xhr.status === 200) { // 判断接口调用成功的重要标识            setTimeout(()=> {              alert('上传成功')              // window.location.href="/"            },1000)          }        }        // 进度条        function setProgress(event) {          console.log(event)          if (event.lengthComputable) {           // 先判断这个上传进程是否有这个文件长度的判断            loaded = event.loaded             // 已经加载的字节            total = event.total             // 上传伊始时候计算的总字节数            var complete = Number.parseInt(event.loaded / event.total * 100);            // 取百分比            progress.style.width = complete + '%';            progress.innerHTML = complete + '%';            // css 偷了懒,用了bootstrap4的css          }        }        // 图片预览        function previewImage(event) {          var reader = new FileReader();           // h5 的新属性           reader.  = function (event) {            image.src = event.target.result;             // 这里是用图片 64的字符串将图片显示出来,用作图片上传预览          };          reader.readAsDataURL(event.target.files[0]);        }        //++++++++++++++++++++++++++++++++++++++++++++        xhr. start = function(){          console.log("上传开始");            }        btn.  = function(){          xhr.abort();          console.log("上传被终止.");          progress.style.width = 0 + '%';          progress.innerHTML = 0 + '%';          // 这里调用取消上传的代码        };        xhr.ontimeout = function(){          console.log('上传超时.');        }        // xhr.timeout = 50000; // 默认为0 没有时间限制        // xhr.  = function(){        //   console.log("The transfer has been canceled by the user.");        // }        xhr.  = function(){          console.log("上传错误,可能是断网了,也可能是断请求服务了.");           // 这里存在异步传输问题          return        }        xhr. end = function(){          console.log("请求结束");           // 发送上传的请求,至于有没有上传成功,不清楚,可能失败 成功,这里只是请求结束了         }        // +++++++++++++++++++++++++++++++++++++++++++      })();  </ ></body></html>

 

2、后端接口(nodejs)

app.js

   const express = require('express');    const upload = require('multer')({ dest: 'uploads/' });    const path = require('path');    const fs = require('fs');    const port = 8088;        let  app = express();        app.set('port', port);    // index.html, index.js放在static文件夹中    app.use(express.static(path.join(__dirname, 'static')));        // app.get('/', (req, res) => {    //   res.redirect('upload2.html');    // });        // 路由/ajax-upload 就回渲染 upload.html 页面    app.get('/ajax-upload', function(req, res){        res.sendFile('upload.html', { root: __dirname });      });      app.post('/upload', upload.single('test-upload'), (req, res) => {      // 没有附带文件      if (!req.file) {        res.json({ ok: false });        return;      }          // 重命名文件      let oldPath = path.join(__dirname, req.file.path);      let newPath = path.join(__dirname, 'uploads/' + req.file.originalname);      fs.rename(oldPath, newPath, (err) => {        if (err) {          res.json({ ok: false });          console.log(err);        } else {          res.json({ ok: true });        }      });    });    // 这里还没有做上传取消 删除文件的操作    app.get('/abort', upload.single('test-upload'), (req, res)=>{      console.log(req, 'abort') // 删除刚才上传的文件    })        app.listen(port, () => {      console.log("[Server] localhost:" + port);    });

 

注:接口使用

  • 环境:nodejs
  • 项目结构 
    • static(图片如下) 
      • app.js
      • upload.html
      • uploads
  • 框架包express: npm install express –save
  • 上传包multer :npm install multer –save
  • 启动: node app.js

文件结构

以上代码可以直接复制运行:

3、解释

3.1.前端

上传简述: 前端的选择文件,掉后端上传接口,利用ajax技术将文件上传的服务器。
前端要知道后端是否上传成功或者状态,就得需要后端返回给我们的状态,最简单的就是上传成功或者失败,再者需要知道进度的就要利用xhr 的进程方法了。
  • ajax 的原理就是利用浏览器的 HttRequest 这个对象,因为IE浏览器不是这对象,如果要兼容的话 ,可以封装一个XHR 对象,代码可以看后面的附属部分:

  • HttRequest 对象有多个方法,监控ajax 上传的进度主要利用这些属性,来达到我们的目标

  • 下面是部分属性(方法)介绍,这里是MDN的介绍 xhr 

    • start 获取开始
    • onprogress 数据传输进行中
    • 获取操作终止
    • 获取失败
    • 获取成功
    • ontimeout 获取操作在用户规定的时间内未完成
    • end 获取完成(不论成功与否)

* 对xhr.upload.onprogress的解释

这里监控进度主要看这里的属性值的变化,如下图 
onprogress的属性值
具体的代码片段解释可以查看我上面的代码注释

3.2.后端

这里使用的nodejs的一个接口,之前我的用的是将前端预览图片的 64的字符串传到后端,然后后端解析这个 64的字符串,生成图片,保存在磁盘中,但是会出现问题,进度不太好显示,

所以查了相关资料,借用了某位大神的写法,直接上传文 件;还有一个就是multer包,利用这个进行上传。

这里项目也是一个后端渲染的方式,将页面渲染好,然后发送给前端。

4、附属代码:

4.1.兼容的 HttpRequest代码段

function  HttpRequest(){    if (typeof  HttpRequest != "undefined"){    return new  HttpRequest();    } else if (typeof ActiveX  != "undefined"){        if (typeof arguments.callee.activeXString != "string"){        var versions = [ "MS 2. Http.6.0", "MS 2. Http.3.0",        "MS 2. Http"],        i, len;        for (i=0,len=versions.length; i < len; i++){            try {                new ActiveX (versions[i]);                arguments.callee.activeXString = versions[i];            break;            } catch (ex){                //跳过            }        }    }         return new ActiveX (arguments.callee.activeXString);    } else {        throw new Error("No XHR   available.");    }}

 

4.2.nodejs 处理 64字符串

node包:formidable 
img 64Arr: 前端传值过来的 64字符串的多张图片的数组

for(var i = 0;i<img 64Arr.length;i++) {    var imgname    = util.randomStr(); // 随机字符串的方法    imgname    = 'assets/img/'+ imgname + '.png';    var  64     = img 64Arr[i].replace(/^data:image/w+; 64,/, "");    //去掉图片 64码前面部分data:image/png; 64    var dataBuffer = new Buffer( 64, ' 64'); //把 64码转成buffer对象,    console.log('dataBuffer是否是Buffer对象:'+Buffer.isBuffer(dataBuffer));    fs.writeFile(imgname,dataBuffer,function(err){//用fs写入文件      if(err){          console.log(err);      }else{          console.log('图片上传成功!');      }    })    newimgarr.push(imgname.replace("assets",""));}

github地址:https://github.com/adouwt/ajax-upload


前端上传这块已经封装了一个基于vue的插件,

GitHub地址:https://github.com/adouwt/vue-upload    

npm 官网上的数据显示居然已经有一定的下载量,实在很惊讶,不过也很欢迎大家学习使用,有bug,及时告知于我

 https://www.npmjs.com/package/vue-ajax-upload

如有错误,敬请指出!

这里提供了一个demo演示如下, ps:个人服务器存储较小,只是用来展示,后端是个小白,没有做一些文件过滤和后端文件风险校验,大神请绕行哈,还有请手下留情哈!
戳我

收藏 打印