upload和FileReade

Posted by 小兵兵 on Friday, May 24, 2019

目录

上传进度

前台

版本一

  • HTML5标签自带的进度条标签<meter>

  • 上传进度oAjax.upload.onprogress

上传进度.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title></title>
    <script>
    window.onload=function (){
      let oF=document.getElementById('f1');
      let oBtn=document.getElementById('btn1');

      oBtn.onclick=function (){
        let data=new FormData();

        Array.from(oF.files).forEach(file=>{
          data.append('f1', file);
        });

        //
        let oAjax=new XMLHttpRequest();



        //POST
        oAjax.open('POST', `http://localhost:8080/api`, true);

        oAjax.upload.onprogress=function (ev){
          let oM=document.getElementById('m1');

          oM.value=100*ev.loaded/ev.total;
        };

        oAjax.send(data);

        /*

        oAjax.onreadystatechange=function (){
          if(oAjax.readyState==4){
            if(oAjax.status>=200 && oAjax.status<300 || oAjax.status==304){
              alert('成功');
            }else{
              alert('失败');
            }
          }
        };*/
      };
    };
    </script>
  </head>
  <body>
    <meter id="m1" value="" min="0" max="100" style="width:500px;"></meter><br>
    <input type="file" id="f1" multiple /><br>
    <input type="button" value="提交" id="btn1">
  </body>
</html>

版本二

  • 自己创建进度条标签

  • 绑定事件监听oAjax.upload.addEventListener

上传进度2.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title></title>
    <style media="screen">
    .parent {width:500px; height:20px; border:1px solid black;}
    .child {width:0; height:100%; background:green;}
    </style>
    <script>
    window.onload=function (){
      let oF=document.getElementById('f1');
      let oBtn=document.getElementById('btn1');

      oBtn.onclick=function (){
        let data=new FormData();

        Array.from(oF.files).forEach(file=>{
          data.append('f1', file);
        });

        //
        let oAjax=new XMLHttpRequest();

        //POST
        oAjax.open('POST', `http://localhost:8080/api`, true);

        console.log(oAjax);

        oAjax.upload.addEventListener('progress', function (ev){
          /*let oM=document.getElementById('m1');

          oM.value=100*ev.loaded/ev.total;*/

          let oChild=document.getElementsByClassName('child')[0];

          oChild.style.width=100*ev.loaded/ev.total+'%';
        }, false);

        oAjax.send(data);

        /*

        oAjax.onreadystatechange=function (){
          if(oAjax.readyState==4){
            if(oAjax.status>=200 && oAjax.status<300 || oAjax.status==304){
              alert('成功');
            }else{
              alert('失败');
            }
          }
        };*/
      };
    };
    </script>
  </head>
  <body>
    <div class="parent">
      <div class="child">

      </div>
    </div>
    <input type="file" id="f1" multiple /><br>
    <input type="button" value="提交" id="btn1">
  </body>
</html>

版本三

  • 下载进度oAjax.onprogress

下载进度.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title></title>
    <style media="screen">
    .parent {width:500px; height:20px; border:1px solid black;}
    .child {width:0; height:100%; background:green;}
    </style>
    <script>
    window.onload=function (){
      let oF=document.getElementById('f1');
      let oBtn=document.getElementById('btn1');

      oBtn.onclick=function (){
        let data=new FormData();

        Array.from(oF.files).forEach(file=>{
          data.append('f1', file);
        });

        //
        let oAjax=new XMLHttpRequest();

        //POST
        oAjax.open('POST', `http://localhost:8080/api`, true);

        oAjax.onprogress=function (ev){
          console.log(ev);
        };

        oAjax.upload.addEventListener('progress', function (ev){
          /*let oM=document.getElementById('m1');

          oM.value=100*ev.loaded/ev.total;*/

          let oChild=document.getElementsByClassName('child')[0];

          oChild.style.width=100*ev.loaded/ev.total+'%';
        }, false);

        oAjax.send(data);

        /*

        oAjax.onreadystatechange=function (){
          if(oAjax.readyState==4){
            if(oAjax.status>=200 && oAjax.status<300 || oAjax.status==304){
              alert('成功');
            }else{
              alert('失败');
            }
          }
        };*/
      };
    };
    </script>
  </head>
  <body>
    <div class="parent">
      <div class="child">

      </div>
    </div>
    <input type="file" id="f1" multiple /><br>
    <input type="button" value="提交" id="btn1">
  </body>
</html>

版本四

  • 下载进度绑定事件监听document.addEventListener

下载进度2.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title></title>
    <style media="screen">
    .parent {width:500px; height:20px; border:1px solid black;}
    .child {width:0; height:100%; background:green;}
    </style>
    <script>
    document.addEventListener('progress', function (){
      console.log('a');
    }, false);
    </script>
  </head>
  <body>
    <form id="form1" action="http://localhost:8080/api" method="post" enctype="multipart/form-data">
      <input type="file" multiple>
      <input type="submit" value="上传">
    </form>
  </body>
</html>

后台

  • 解决跨域,判断请求头中是否携带req.headers['origin']字段

express_server.js

const express=require('express');     //主体
const body=require('body-parser');    //接收普通POST数据
const multer=require('multer');       //接收文件POST数据
const mysql=require('mysql');

let db=mysql.createPool({host: 'localhost', port: 3309, user: 'root', password: '', database: '20180208'});

let server=express();
server.listen(8080);

//中间件
server.use(body.urlencoded({extended: false}));

let multerObj=multer({dest: './upload/'});
server.use(multerObj.any());

//处理请求
server.use('/api', (req, res)=>{
  if(req.headers['origin']=='null' || req.headers['origin'].startsWith('http://localhost')){
    res.setHeader('Access-Control-Allow-Origin', '*');
  }

  let arr=[];
  req.files.forEach(file=>{
    arr.push(`('${file.originalname}', '${file.filename}', ${Math.floor(Date.now()/1000)})`);
  });

  let sql=`INSERT INTO image_table (originalname, filename, time) VALUES${arr.join(',')}`;

  //console.log(sql);
  db.query(sql, (err)=>{
    if(err){
      res.send('不OK');
    }else{
      res.send("OK");
    }
  });
});

//
server.use(express.static('./www/'));

上传进度条实现注意

  • oAjax.upload.onprogress必须放在oAjax.send(data)前面
  • 服务器必须能处理OPTIONS请求,oAjax加了upload会发送OPTIONSPOST2次请求
    • 对于通用服务器,我们不用担心,他们会自己进行处理
    • 对于NodeJS服务,使用express框架,使用server.use

拖拽上传

  • 拖拽松手事件drop
    • 绑定事件监听阻止默认行为,ev.preventDefault()
    • 按钮阻止默认行为,return false
  • 获取文件ev.dataTransfer.files
  • 数据封装,使用FormData封装文件数据
  • 发送,oAjax.send(data)

文件拖拽.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title></title>
    <style media="screen">
    * {margin:0; padding:0}
    .box {width:400px; height:200px; background:#CCC; border:1px solid black; line-height:200px; position:absolute; left:50%; top:50%; margin-left:-200px; margin-top:-100px; text-align:center; display:none;}
    </style>
    <script>
    window.onload=function (){
      let oBox=document.querySelector('.box');
      let timer;

      document.addEventListener('dragover', (ev)=>{
        clearTimeout(timer);

        oBox.style.display='block';

        timer=setTimeout(function (){
          oBox.style.display='none';
        }, 300);

        ev.preventDefault();
      }, false);

      oBox.addEventListener('dragenter', ()=>{
        oBox.innerHTML='请松手';
      }, false);
      oBox.addEventListener('dragleave', ()=>{
        oBox.innerHTML='请把文件拖到这儿';
      }, false);

      oBox.addEventListener('drop', (ev)=>{
        let data=new FormData();

        Array.from(ev.dataTransfer.files).forEach(file=>{
          data.append('f1', file);
        });

        let oAjax=new XMLHttpRequest();

        //POST
        oAjax.open('POST', `http://localhost:8080/api`, true);

        oAjax.upload.addEventListener('progress', function (ev){
          let oM=document.querySelector('#m1');

          oM.value=100*ev.loaded/ev.total;
        }, false);

        oAjax.send(data);

        ev.preventDefault();

        oAjax.onreadystatechange=function (){
          if(oAjax.readyState==4){
            if(oAjax.status>=200 && oAjax.status<300 || oAjax.status==304){
              alert('成功');
            }else{
              alert('失败');
            }
          }
        };
      }, false);
    };
    </script>
  </head>
  <body>
    <meter id="m1" min="0" max="100" style="width:100%;"></meter>
    <div class="box">
      请把文件拖到这儿
    </div>
  </body>
</html>

读取文件FileReader

前台

版本一

  • 文件读取 方法reader.readAsDataURL(file)可以将图片文件转换为base64编码
  • 传输数据可以通过二进制和base64来传输
    • base64可以把二进制数据表现成字符串
    • 只要能出现地址src的地方,都能用Base64
    • 一般小图标不要引用地址,直接放个base64可以优化网络性能
    • 维护麻烦,base64编码会把文件体积变大
  • 当读取操作成功完成时调用reader.onload

读取文件.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title></title>
    <style media="screen">
    * {margin:0; padding:0}
    .box {width:400px; height:200px; background:#CCC; border:1px solid black; line-height:200px; position:absolute; left:50%; top:50%; margin-left:-200px; margin-top:-100px; text-align:center; display:none;}
    </style>
    <script>
    window.onload=function (){
      let oBox=document.querySelector('.box');
      let timer;

      document.addEventListener('dragover', (ev)=>{
        clearTimeout(timer);

        oBox.style.display='block';

        timer=setTimeout(function (){
          oBox.style.display='none';
        }, 300);

        ev.preventDefault();
      }, false);

      oBox.addEventListener('dragenter', ()=>{
        oBox.innerHTML='请松手';
      }, false);
      oBox.addEventListener('dragleave', ()=>{
        oBox.innerHTML='请把文件拖到这儿';
      }, false);

      oBox.addEventListener('drop', (ev)=>{
        let file=ev.dataTransfer.files[0];

        //读取文件
        let reader=new FileReader();

        reader.onload=function (){
          document.write(reader.result);
        };

        //base64
        reader.readAsDataURL(file);


        ev.preventDefault();
      }, false);
    };
    </script>
  </head>
  <body>
    <div class="box">
      请把文件拖到这儿
    </div>
  </body>
</html>

版本二

  • 判断文件类型,file.type.startsWith('image/')

读取文件2.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title></title>
    <style media="screen">
    * {margin:0; padding:0; list-style: none}
    .box {width:400px; height:200px; background:#CCC; border:1px solid black; line-height:200px; position:absolute; left:50%; top:50%; margin-left:-200px; margin-top:-100px; text-align:center; display:none;}

    .img_list {overflow:hidden;}
    .img_list li {float:left; width:200px; height:200px; border:3px solid #666; margin:10px; position:relative;}
    .img_list li img {width:100%; height:100%;}
    .img_list li .del_btn {position:absolute; right:0; top:0;}
    </style>
    <script>
    window.onload=function (){
      let oUl=document.querySelector('.img_list');
      let oBox=document.querySelector('.box');
      let timer;

      document.addEventListener('dragover', (ev)=>{
        clearTimeout(timer);

        oBox.style.display='block';

        timer=setTimeout(function (){
          oBox.style.display='none';
        }, 300);

        ev.preventDefault();
      }, false);

      oBox.addEventListener('dragenter', ()=>{
        oBox.innerHTML='请松手';
      }, false);
      oBox.addEventListener('dragleave', ()=>{
        oBox.innerHTML='请把文件拖到这儿';
      }, false);

      oBox.addEventListener('drop', (ev)=>{
        Array.from(ev.dataTransfer.files).forEach(file=>{
          if(!file.type.startsWith('image/')){
            return;
          }

          let reader=new FileReader();

          reader.onload=function (){
            let oLi=document.createElement('li');
            oLi.file=file;
            oLi.innerHTML='<img src="a.png" alt=""><a href="javascript:;" class="del_btn">删除</a>';

            let oImg=oLi.children[0];
            oImg.src=this.result;

            let oBtnDel=oLi.children[1];
            oBtnDel.onclick=function (){
              oUl.removeChild(oLi);
            };

            oUl.appendChild(oLi);
          };

          reader.readAsDataURL(file);
        });

        ev.preventDefault();
      }, false);

      //真的上传
      let oBtnUpload=document.querySelector('#btn_upload');
      oBtnUpload.onclick=function (){
        let data=new FormData();

        Array.from(oUl.children).forEach(li=>{
          data.append('f1', li.file);
        });

        //
        let oAjax=new XMLHttpRequest();

        //POST
        oAjax.open('POST', `http://localhost:8080/api`, true);
        oAjax.send(data);

        oAjax.onreadystatechange=function (){
          if(oAjax.readyState==4){
            if(oAjax.status>=200 && oAjax.status<300 || oAjax.status==304){
              alert('成功');
            }else{
              alert('失败');
            }
          }
        };
      };
    };
    </script>
  </head>
  <body>
    <ul class="img_list">
      <!--<li>
        <img src="a.png" alt="">
        <a href="javascript:;" class="del_btn">删除</a>
      </li>
      <li>
        <img src="b.png" alt="">
        <a href="javascript:;" class="del_btn">删除</a>
      </li>-->
    </ul>
    <input type="button" name="" value="上传" id="btn_upload">
    <div class="box">
      请把文件拖到这儿
    </div>
  </body>
</html>

版本三

  • 以二进制数据的形式存储数据,reader.readAsArrayBuffer(file)
  • 以字符串形式存储的二进制数据,readAsBinaryString
  • 图片(以及其他二进制数据),readAsDataURL
  • 将文件读取为文本,readAsText

读取文件3.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title></title>
    <style media="screen">
    * {margin:0; padding:0; list-style: none}
    .box {width:400px; height:200px; background:#CCC; border:1px solid black; line-height:200px; position:absolute; left:50%; top:50%; margin-left:-200px; margin-top:-100px; text-align:center; display:none;}

    .img_list {overflow:hidden;}
    .img_list li {float:left; width:200px; height:200px; border:3px solid #666; margin:10px; position:relative;}
    .img_list li img {width:100%; height:100%;}
    .img_list li .del_btn {position:absolute; right:0; top:0;}
    </style>
    <script>
    window.onload=function (){
      let oUl=document.querySelector('.img_list');
      let oBox=document.querySelector('.box');
      let timer;

      document.addEventListener('dragover', (ev)=>{
        clearTimeout(timer);

        oBox.style.display='block';

        timer=setTimeout(function (){
          oBox.style.display='none';
        }, 300);

        ev.preventDefault();
      }, false);

      oBox.addEventListener('dragenter', ()=>{
        oBox.innerHTML='请松手';
      }, false);
      oBox.addEventListener('dragleave', ()=>{
        oBox.innerHTML='请把文件拖到这儿';
      }, false);

      oBox.addEventListener('drop', (ev)=>{
        let file=ev.dataTransfer.files[0];
        let reader=new FileReader();

        console.log(reader);
        reader.onload=function (){
          console.log(this.result);
        };

        reader.readAsArrayBuffer(file);

        ev.preventDefault();
      }, false);
    };
    </script>
  </head>
  <body>
    <div class="box">
      请把文件拖到这儿
    </div>
  </body>
</html>

后台

将读取的文件入库

  • 连接数据库mysql.createPool
  • 批量插入

express_server.js

const express=require('express');     //主体
const body=require('body-parser');    //接收普通POST数据
const multer=require('multer');       //接收文件POST数据
const mysql=require('mysql');

let db=mysql.createPool({host: 'localhost', port: 3309, user: 'root', password: '', database: '20180208'});

let server=express();
server.listen(8080);

//中间件
server.use(body.urlencoded({extended: false}));

let multerObj=multer({dest: './upload/'});
server.use(multerObj.any());

//处理请求
server.use('/api', (req, res)=>{
  if(req.headers['origin']=='null' || req.headers['origin'].startsWith('http://localhost')){
    res.setHeader('Access-Control-Allow-Origin', '*');
  }

  let arr=[];
  req.files.forEach(file=>{
    arr.push(`('${file.originalname}', '${file.filename}', ${Math.floor(Date.now()/1000)})`);
  });

  let sql=`INSERT INTO image_table (originalname, filename, time) VALUES${arr.join(',')}`;

  //console.log(sql);
  db.query(sql, (err)=>{
    if(err){
      res.send('不OK');
    }else{
      res.send("OK");
    }
  });
});

//
server.use(express.static('./www/'));

ajax版本

  • ajax2.0携带有oAjax.upload属性

ajax版本.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title></title>
    <style media="screen">
    .parent {width:500px; height:20px; border:1px solid black;}
    .child {width:0; height:100%; background:green;}
    </style>
    <script>
    window.onload=function (){
      var oBtn=document.getElementById('btn1');

      oBtn.onclick=function (){
        var oAjax=new XMLHttpRequest();

        if(oAjax.upload){
          alert('2.0');
        }else{
          alert('1.0');
        }
      };
    };
    </script>
  </head>
  <body>
    <input type="button" value="提交" id="btn1">
  </body>
</html>