原生JS上傳圖片、保存圖片(ajax,form兩種提交)


1. 技術棧前端/后端 原生JS  test

2.代碼部分

  2.1 前端

    2.1.1 Form表單提交方式  文件名: upload.form.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>upload by form</title>
  </head>
  <body>
    <form action="/upload" enctype="multipart/form-data" method="post">
      <input type="file" name="avatar" id="avatar" multiple="multiple" />
      <input type="submit" value="form上傳頭像" id="submit" />
    </form>
    <img id="img" />
  </body>
  <script>
    window.onload = () => {
      const avatar = document.getElementById("avatar");
      const img = document.getElementById("img");
      avatar.onchange = e => {
        const file = e.target.files[0];
        //創建讀取文件的對象
        const reader = new FileReader();
        //使用該對象讀取file文件
        reader.readAsDataURL(file);
        //讀取文件成功后執行的方法函數
        reader.onload = function(e) {
          //讀取成功后返回的一個參數e,整個的一個進度事件
          //選擇所要顯示圖片的img,要賦值給img的src就是e中target下result里面
          //的base64編碼格式的地址
          img.src = e.target.result;
        };
      };
    };
  </script>
</html>

    2.1.2  Ajax異步提交方式 文件名: upload.ajax.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>upload by Ajax</title>
  </head>
  <body>
    <input type="file" id="avatar" multiple="multiple" />
    <button type="button" id="submit">ajax上傳頭像</button>
    <img src="" id="img" />
  </body>
  <script>
    window.onload = () => {
      const btn = document.getElementById("submit");
      const img = document.getElementById("img");
      const avatar = document.getElementById("avatar");
      avatar.onchange = e => {
        const file = e.target.files[0];
        const reader = new FileReader();
        reader.readAsDataURL(file);
        reader.onload = e => {
          img.src = e.target.result;
        };
      };
      submit.onclick = () => {
        if(!avatar.files[0]) {
          alert('選擇圖片!')
          return false
        }
        const formData = new FormData();
        formData.append("avatar", avatar.files[0]);
        const xhr = new XMLHttpRequest();
        xhr.onreadystatechange = () => {
          if (xhr.readyState === 4 && xhr.status === 200) {
            console.log(xhr.responseText)
          }
        };
        // 上傳進度
        xhr.upload.addEventListener(
          "progress",
          e => {
            if (e.lengthComputable) {
              console.log("percent: ", (e.loaded / e.total) * 100 + "%");
            }
          },
          false
        );
        // 上傳路徑這里寫成相對路徑 避免環境變化
        xhr.open("POST", "./upload");
        xhr.send(formData);
      };
    }; 
  </script>
</html>

  2.2 后端部分   文件名: upload.2.js

const http = require("http");
const fs = require("fs");
const formidable = require("formidable");
const pathFn = require("path");
http
  .createServer((req, res) => {
    if (req.url === "/upload" && req.method === "POST") {
      const form = new formidable.IncomingForm();
      const savePath = pathFn.join(__dirname, "/upload");
      // 檢查文件加是否已經存在 這里用同步方法
      if (!fs.existsSync(savePath)) {
        fs.mkdirSync(savePath);
      }
      form.uploadDir = savePath;
      form.parse(req, (err, fields, files) => {
        res.writeHead(200, { "Content-Type": "text/plain" });
        // 取文件路徑 和 文件名字
        const { path, name } = files.avatar;
        // 重命名
        fs.rename(path, pathFn.join(savePath, "/", name), err => {
          if (err) {
            res.writeHead(200, { "Content-Type": "text/plain" });
            res.end(err);
          }
          res.writeHead(200, { "Content-Type": "application/json" });
          res.end(JSON.stringify({code: 200, data: '/upload/' + name}));
        });
      });
    } else if (req.url === "/user-ajax") {
      const html = fs.readFileSync("./upload.ajax.html");
      res.writeHead(200, { "Content-Type": "text/html; charset=UTF8" });
      res.end(html);
    } else if (req.url === "/user-form") {
      const html = fs.readFileSync("./upload.form.html");
      res.writeHead(200, { "Content-Type": "text/html; charset=UTF8" });
      res.end(html);
    } else if (req.url === "/upload-ok") {
      const html = fs.readFileSync("./upload.ok.html");
      res.writeHead(200, { "Content-Type": "text/html; charset=UTF8" });
      res.end(html);
    } else {
      res.writeHead(200, { "Content-Type": "text/html; charset=UTF8" });
      res.end("No found!");
    }
  })
  .listen(7777);

3. 兩種提交方式的不同

  表單提交成功后, 直接跳轉到了 /upload 返回 { code: 200, data: '/upload/XXXXX.png' }

  ajax異步提交成功后, 是返回 json 數據, 頁面不刷新.

  這里的處理方案, 如果是用form表單提交, 可以修改后端返回直接重定向到一個提交成功頁面(upload.ok.html

          // ajax提交 成功之后返回 json
          // res.writeHead(200, { "Content-Type": "application/json" });
          // res.end(JSON.stringify({code: 200, data: '/upload/' + name}));
          
          // form表單 成功之后 重定向頁面
          res.writeHead(302, { 'Location': './upload-ok'})

4. 補充說明

  這里博主 試着抓取  ajax 與 form表單 兩種提交方式的 req 對象對比,  在 本機 localhost 的環境下 是有一個  Sec-fetch-mode 的值的別去 form 是 navigate , ajax 是 cors , 但是走網絡請求后 是沒有 Sec-fetch-mode ,實在找不到兩者如何來區分;

  記得Express.js 框架提供一個 req.xhr 屬性,如果請求由 Ajax 發起將會返回 true , 后期研究之后再補充;

 

5. 資料來源指向 .

FormData 對象的使用

FileReader


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM