文件拖拽上传

403 阅读3分钟

文件拖拽上传

一、JavaScrip

1. 搭建后台环境

image.png

1.1 下载依赖

npm init -y
npm install express
npm install formidable

1.2 复制代码

// app.js 

// 引入express框架
const express = require("express");
// 路径处理模块
const path = require("path");
const formidable = require("formidable");
// 创建web服务器
const app = express();

app.use((req, res, next) => {
  // 1. 允许那些客户端访问我
  // * 代表允许所有的客户端访问我
  // res.header('Access-Control-Allow-Origin', 'http://localhost:3000');
  res.header("Access-Control-Allow-Origin", "*");
  // 2. 允许客户端使用哪些请求方法访问我
  res.header("Access-Control-Allow-Methods", "get,post");
  next();
});

// 实现文件上传的路由
app.post("/upload", (req, res) => {
  // console.log(req);
  // 创建formidable表单解析对象
  const form = new formidable.IncomingForm();
  // // 设置客户端上传文件的存储路径
  form.uploadDir = path.join(__dirname, "public", "uploads");
  // // 保留上传文件的后缀名字
  form.keepExtensions = true;
  // // 解析客户端传递过来的FormData对象
  form.parse(req, (err, fields, files) => {
    // 将客户端传递过来的文件地址响应到客户端
    console.log(files);
    res.send({
      path: files.filename.path,
    });
    // res.send("ok");
  });
});

// 静态资源访问服务功能
app.use(express.static(path.join(__dirname, "public")));

// 监听端口
app.listen(3000);
// 控制台提示输出
console.log("服务器启动成功访问: localhost:3000");

2. 基本骨架

  • 在拖动目标上触发事件 (源元素) :

    • ondragstart - 用户开始拖动元素时触发
    • ondrag - 元素正在拖动时触发
    • ondragend - 用户完成元素拖动后触发
  • 释放目标时触发的事件:

    • ondragenter - 当被鼠标拖动的对象进入其容器范围内时触发此事件
    • ondragover - 当某被拖动的对象在另一对象容器范围内拖动时触发此事件
    • ondragleave - 当被鼠标拖动的对象离开其容器范围内时触发此事件
    • ondrop - 在一个拖动过程中,释放鼠标键时触发此事件

注意:  在拖动元素时,每隔 350 毫秒会触发 ondragover 事件。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Document</title>
    <style type="text/css">
      .container {
        padding-top: 60px;
      }
      .dragger {
        width: 200px;
        height: 200px;
        background-color: pink;
        text-align: center;
        line-height: 100px;
      }
    </style>
  </head>
  <body>
    <div class="container">
      <div class="dragger">拖拽上传</div>
      <p class="pathContent"></p>
    </div>
  </body>
</html>

3. 阻止浏览器默认打开文件

document.addEventListener("drop", function (e) {
  // 拖拽释放
  e.preventDefault();
});
document.addEventListener("dragover", function (e) {
  //拖来拖去
  e.preventDefault();
});     

4. 获取文件

// 获取拖拽容器
var dragger = document.querySelector(".dragger");
// 上传文件后路径显示容器
var pathContent = document.querySelector(".pathContent");

drop 事件下的 e.dataTransfer.files 就是存放拖拽的文件的类数组

// 监听拖拽释放事件
dragger.addEventListener("drop", function (e) {
    e.preventDefault();
    // e.dataTransfer.files 是类数组,将类数组转换成真正的数组
    var files = Array.from(e.dataTransfer.files);
}

5. 上传文件

上传文件就是正常发 ajax 请求前后端交互 Ajax,Fetch

 // 监听拖拽施放事件
dragger.addEventListener("drop", function (e) {
  e.preventDefault();
  // e.dataTransfer.files 是类数组,将类数组转换成真正的数组
  var files = Array.from(e.dataTransfer.files);
  // 创建空的formData表单对象
  var formData = new FormData();
  // 将用户选择的文件追加到formData表单对象中
  formData.append("filename", files[0]);
  // 创建 ajax 对象
  const xhr = new XMLHttpRequest();
  // 设置请求方式和路径
  xhr.open("post", "http://localhost:3000/upload");
  // 发送请求
  xhr.send(formData);
  // 监听服务器端响应给客户端的数据
  xhr.onload = function () {
    if (xhr.status === 200) {
      var result = JSON.parse(xhr.responseText);
      console.log(result.path);
      pathContent.innerHTML = "文件路径" + result.path;
    }
  };
});

二、React

React 上传文件步骤原生 js 一样, 不过更简单了

import React, { memo, useState } from "react";

export default memo(function App() {
  const [path, setPath] = useState("");

  const handleDrop = (e) => {
    e.preventDefault();
    // 获取到文件
    const files = Array.from(e.dataTransfer.files);
    // 上传文件步骤就和之前一样了
  };
  return (
    <div>
      <div
        className="dragger"
        // 禁止浏览器默认行为
        onDrop={handleDrop}
        onDragOver={(e) => {
          e.preventDefault();
        }}
        style={{
          width: "200px",
          height: "200px",
          backgroundColor: "pink",
          textAlign: "center",
          lineHeight: "200px",
        }}
      >
        拖拽上传
      </div>
      <p>{path}</p>
    </div>
  );
});

不过这样组件太简陋了,我们可以添加组件添加一些生命周期,上传之前,上传中,上传成功,上传失败等,和一些参数,如请求头,文件名了,是否可以多选了等等。