封装一个uploader组件(纯Javascript版本)

1,696 阅读5分钟

一些要提前学习的知识:

  • input 使用 type=file 实现文件上传;
  • transform: translateX()实现加载进度条动画;
  • 原生 XMLHttpRequest 请求的封装;
  • 使用 FormData
  • 后端使用 node.js 完成上传接口。

input

  • input 使用 type=file 实现文件上传
  • accept 属性可以规定文件上传的文件类型,可以接收的参数有: | 值 | 描述 | | ---- | ---- | | audio/* | 接收所有的声音文件| | video/* | 接收所有的视频文件 | | image/* | 接收所有的图片文件 | | image/png,image/jpeg | 接收 png,jpe,jpg,jpeg 图片文件 |

更多 MIME 类型列表:www.w3school.com.cn/media/media…

Live Server

VSCode 中使用 live-server 插件,live-server是可以运行前端静态文件的一个服务器。可以实时更新我们修改的 html 文件。

XMLHttpRequest 封装

使用 Promise 对 xhr 请求进行了封装:在 onload 事件中对返回码不正确的情况进行了处理;onerror 事件中捕获异常。

  • Ajax = Asynchronous Javascript and XML (异步的 Javascript 和 XML);AJAX 在不重新加载整个页面的情况下,实现与服务器交换数据并更新部分网页的方法。
  • xhr.open(method,url,async); 第三个参数 true(异步),表示请求是 AJAX的,即JavaScript 无需等待服务器的响应,而是在等待服务器响应时执行其他脚本,当响应就绪后对响应进行处理。
  • 上传的 process 事件属于 XMLHttpRequest.upload 对象。
  • 下载的 process 事件属于 XMLHttpRequest 对象。
function postFile(url, data) {
    return new Promise((resolve, reject) => {
        const xhr = new XMLHttpRequest();
        xhr.onload = function () {
            //将错误码返回
            if(xhr.status<200||xhr.status>=300){
                reject(xhr.status);
            }
            resolve(xhr.response);
        }
        //获取异常
        xhr.onerror = function (e) {
            reject(e);
        }
        if (xhr.upload) {
            xhr.upload.onprogress = function progress(e) {
                if (e.total > 0) {
                    const percent = (e.loaded / e.total) * 100;
                    e.percent = percent;
                    console.log("percent: " + percent)
                }
            };
        }

        xhr.open('POST', url, true);
        //xhr.setRequestHeader('Content-Type', 'application/json');
        xhr.send(data);
    })
}

补充:

  • xhr.setRequestHeader(); 可以用来设置请求头信息;位置要在 xhr.open() 之后设置才可以。
  • 因为文件上传用到了 FormData 对象,不需要重复设置请求头的 Content-Type 信息。

Content-Type

Content-Type 可以通过 xhr.setRequestHeader('Content-Type', 'application/json'); 在请求头中定义请求数据的类型格式。服务端也可以通过设置响应头的 Content-Type 来告诉浏览器响应数据的格式。 常用的 Content-Type 取值有:

描述
application/jsonJSON数据格式
application/x-www-form-urlencoded中默认的encType,form表单数据被编码为key/value格式发送到服务器(表单默认的提交数据的格式)
multipart/form-data需要在表单中进行文件上传时,就需要使用该格式

更多:www.runoob.com/http/http-c…

另外原生的 form 表单可以通过设置 enctype 属性来设置请求数据的格式,但是我们现在一般都不用原生 form 表单向后端发送请求了。form 表单向后端发送请求存在页面刷新的问题,现在的做法只是用 form 表单展现数据而已。

form 的使用方式:<form enctype="value">

描述
application/x-www-form-urlencoded在发送前编码所有字符(默认)
multipart/form-data不对字符编码。在使用包含文件上传控件的表单时,必须使用该值。
text/plain空格转换为 "+" 加号,但不对特殊字符编码。

FormData

FormData 类型是在XMLHttpRequest 2级定义的,常用的用法有两个:一个是将 form 表单的数据进行序列化,通过 AJAX 发送数据;另一个创建 Content-Type 是 multipart/form-data 类型的数据,常用于文件上传。

<form id="myForm" action="" method="post">
  <input type="text" name="name">名字
  <input type="password" name="psw">密码
  <input type="submit" value="提交">
</form>

我们可以使用这个表单元素作为初始化参数,来实例化一个formData对象

// 获取页面已有的一个form表单
var form = document.getElementById( "myForm");
// 用表单来初始化
var formData = new FormData(form);
// 我们可以根据name来访问表单中的字段
var name = formData.get( "name"); // 获取名字
var psw = formData.get( "psw"); // 获取密码
// 当然也可以在此基础上,添加其他数据
formData.append( "token", "kshdfiwi3rh");

node.js 部分

初始化 npm 项目

npm init --yes

安装需要的中间件:express、multer、fs。

cnpm install multer express fs --save

express

express 可以帮我们启动一个后端服务。本示例采用 CORS(Cross-Origin-Resource-Sharing,跨域资源共享) 解决跨域问题。

const app = express();
// 设置跨域访问
app.all("*", function(request, response, next) {
  // 设置跨域的域名,* 代表允许任意域名跨域
  response.header("Access-Control-Allow-Origin", "http://127.0.0.1:5500"); 
  //设置请求头 header 可以加那些属性
  response.header('Access-Control-Allow-Headers', 'Content-Type, Content-Length, Authorization, Accept, X-Requested-With');
  //设置请求头哪些方法是合法的
  response.header(
    "Access-Control-Allow-Methods",
    "PUT,POST,GET,DELETE,OPTIONS"
  );
  response.header("Content-Type", "application/json;charset=utf-8");
  next();
});

multer

Multer 是一个 node.js 中间件,用于处理 multipart/form-data 类型的表单数据,它主要用于上传文件。 Multer 通过设置可以限制上传的文件大小和类型:

//文件大小 
const limits = {
  fileSize: 1024*1024 //单位是字节
}
//文件类型
const fileFilter = function (req, file, cb) {
  const acceptableMime = ["image/jpeg", "image/png", "image/jpg", "image/gif", "application/zip", "application/x-zip-compressed"];
  // 限制类型
  // null是固定写法
  if (acceptableMime.indexOf(file.mimetype) !== -1) {
    cb(null, true); // 通过上传
  } else {
    cb(null, false); // 禁止上传
    cb(new Error('文件类型错误'));
  }
}
const imageUploader = multer({
  fileFilter,
  limits
}).single("file"); //文件上传预定 name 或者 字段

通过 multer.diskStorage 可以设置文件存储在服务器的位置,可以直接使用相对路径;也可以借助 fs 存储到服务器的绝对路径上。

更多使用:github.com/expressjs/m…

fs

将上传的文件存放在服务器的绝对路径的位置中:

const fs = require('fs');
const createFolder = function(folder){
  try{
    fs.accessSync(folder);
  }catch(e){
    fs.mkdirSync(folder);
  }
};
const uploadFolder = 'C:/upload/';
createFolder(uploadFolder);

node.js 调试

node --inspect server.js

在前端页面的 devtools 工具中会多出来 Open dedicated DevTools for Node.js,点击这个按钮可以进行调试 node.js 服务端代码。

效果

源码

github: github.com/YY88Xu/uplo…

感谢

如果本文有帮助到你的地方,记得点赞哦,这将是我坚持不断创作的动力~

参考:
www.cnblogs.com/tianyuchen/…
www.jianshu.com/p/562cf4baf…
blog.csdn.net/scorpio_h/a…
www.jb51.net/article/162…
blog.csdn.net/walk_man_3/…
www.cnblogs.com/sexintercou…