H 5アップロードファイルをドラッグ&ドロップ+プログレスバー表示

10941 ワード

この文章はH 5のドラッグ&ドロップAPIを利用して,ファイルをブラウザにドラッグ&ドロップする機能を実現している.
ビジネスニーズ:
1、 をブラウザ にドラッグします.2、 にとどまり、ヒント情報はアップロード可能である.3、リリース 、リリース位置 、アップロード操作を実行し、アップロードの進度を表示する.
ドラッグ&ドロップイベント
HTMLのdrag&dropはDOM event modelとmouse eventsから受け継いだdrag eventsを使用しています.典型的なドラッグ操作は、ユーザーがドラッグ可能な要素を選択し、ドラッグ可能な要素にドラッグ(マウスを離さない)し、マウスを解放することです.
ビジネスニーズに応じて、ここで使用するドラッグ・アンド・ドロップ・イベントには、次のものが含まれます.
  • dragoverファイルがアップロード可能領域に入ると
  • がトリガーされる.
  • dragleaveファイルをドラッグしてアップロード可能領域から離れると
  • がトリガーされる.
  • dropドラッグファイルは、アップロード可能領域の解放時に
  • をトリガーする.
    次に、アップロード可能な領域のdom要素を作成します.


    イベントの追加:
    const dragEl=document.getElementById("target");
    
    dragEl.addEventListener("dragover",handleOver)
    dragEl.addEventListener("drop",handleDrop)
    dragEl.addEventListener("dragleave",handleLeave)
    
    //        
    function handleDrop(ev){
        ev.preventDefault();
        //       
        console.log(ev.dataTransfer.files[0])
    }
    function handleOver(ev){
        ev.preventDefault();
        console.log("      ")
    }
    function handleLeave(ev){
        ev.preventDefault();
        console.log("      ")
    }

    追加されたドラッグイベントは、ブラウザのデフォルトイベントをブロックする必要があります.
    ヒント
    良いヒント情報は、ユーザーがより良い使用体験を得ることができ、次にアップロード領域にヒント情報を追加します.

    ...


    スタイルで情報の表示を制御するには、次の手順に従います.
    .u{
        width: 100%;
        height: 95vh;
        display: flex;
        align-items: center;
        justify-content: center;
        transition:background .3s;
    }
    .u [class^="tip"]{
        opacity: .5;
        font-size: 23px;
        text-align: center;
    }
    .u [class^="tip"]{
        display: none;
    }
    .u.init{
        background-color: #f0f0f0;
    }
    .u.init .tip-start{
        display: block;
    }
    .u.actived{
        background-color: #f9f9f9;
        border: 1px dashed #ddd;
    }
    .u.actived .tip-over{
        display: block;
    }
    .u.uploading{
        background-color: #ddd;
    }
    .u.uploading .tip-uploading{
        display: block;
    }
    .u.success{
        background-color: #f5f5f5;
    }
    .u.success .tip-done{
        display: block;
    }
    .u.error{
        background-color: #ffd0d0;
    }
    .u.error .tip-error{
        display: block;
    }

    ここでは、target要素に異なるクラス名を追加することによって、次のように異なる情報のスタイルを制御します.
  • className=".u.init"初期状態
  • className=".u.actived"ターゲットはアップロード可能領域
  • に入る.
  • className=".u.uploading"ファイルが
  • にアップロードされています.
  • className=".u.success"ファイルアップロード成功
  • className=".u.error"ファイルアップロード失敗
  • 次に、ドラッグ・イベントに対応する表示クラス名を追加します.
    function handleDrop(ev){
        ev.preventDefault();
        dragEl.className="u uploading"
        ...
    }
    function handleOver(ev){
        ev.preventDefault();
        dragEl.className="u actived"
    }
    function handleLeave(ev){
        ev.preventDefault();
        dragEl.className="u init"
    }

    ファイルのアップロード
    ファイルがアップロード領域で解放されると、アップロードファイル情報が取得され、FormDataオブジェクトを用いてフォームデータが生成され、アップロード操作が実行される.
    function handleDrop(ev){
        ev.preventDefault();
        dragEl.className="u uploading"
        //       
        const fd = new FormData();
        const file = ev.dataTransfer.files[0];
        fd.append("file",file);
        //       
        upload(fd)
    }
    XMLHttpRequestを生成して、バックエンドにフォーム情報を送信します.
    function upload(data){
        const xhr = new XMLHttpRequest();
        //        
        xhr.open("POST","/upload");
        xhr.responseType = "json";    
        xhr.onload = function(){
            if(xhr.response && xhr.response.success){
                //      ,      
                dragEl.className="u success"
                //       
                setTimeout(()=>dragEl.className="u init",3000);
            }else{
                //     
                dragEl.className="u error";
                console.error(xhr.response.error);
            }
        }
        //   
        xhr.send(data);
    }

    不要なバグの発生を防止するために、ここでアップロード操作を実行する前に、いくつかの判断が必要です.
  • ファイルはまだアップロードされています.この場合、ファイルアップロード領域は
  • で使用できません.
  • ドラッグしたファイルがアップロード要件(ファイルタイプ、ファイルサイズ)
  • に合致するかどうか
    function handleDrop(ev){
        ev.preventDefault();
        //        
        if(dragEl.className.indexOf("uploading")>=0) return;
        ...
        const MAX_SIZE =  200 * 1024 * 1024;
        if(file.size>= MAX_SIZE) return alert("     200mb");
    }

    進捗バーのアップロードxhr.upload.onprogressにより、ファイルのアップロード進捗情報を取得できます.
    xhr.upload.onprogress=function({loaded,total}){
        const precent = (loaded/total)*100;
        console.log(precent)
    }

    dom要素に進捗バーを追加するには、次の手順に従います.

    ...


    プログレスバースタイルを追加するには、次の手順に従います.
    .progress{
        height: 5px;
        width: 300px;
        overflow: hidden;
        position: relative;
        border: 1px solid #999;
    }
    .line{
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        transition:.1s;
        position: absolute;
        background-color: #999;
        transform: translateX(-100%);
    }

    進捗バーonprogressイベント:
    function upload(data){
        ...
        //     
        const precentEl = document.getElementById("precent");
        xhr.upload.onprogress=function({loaded,total}){
            const precent = (loaded/total)*100;
            //     
            precentEl.style.transform = `translateX(-${100-precent}%)`
            //      ,        
            if(precent>=100) setTimeout(() => dragEl.className="u success", 500);
        }
        ...
    }

    バックエンドExpress+multer処理アップロードファイル
    プロセス全体は複雑ではなく、expressおよびmulterによってプロセス全体をシミュレートすることができる.
    コンソールを開き、npmファイルを初期化します.
    npm init -y
    expressmulterを取り付けます.
    npm install express multer --save-dev

    ファイルディレクトリ:
    /- package.json
    /- server.js
    /- index.html
    /- uploads
  • server.js
  • const { resolve } = require("path");
    const express = require("express");
    const app = express();
    const multer = require("multer");
    
    const upload = multer({ dest: resolve(__dirname, "./uploads") });
    
    app.use(express.static(__dirname));
    app.post("/upload", upload.single("file"), (req, res) => {
      res.send({ success: true, message: req.file });
    });
    
    app.listen(3000, () => console.log(`Serving on localhost:3000`));
  • index.html :
  • 
    
    
        
        
            +     
        
    
    
    

    ...

    const dragEl=document.getElementById("target"); dragEl.addEventListener("dragover",handleOver) dragEl.addEventListener("drop",handleDrop) dragEl.addEventListener("dragleave",handleLeave) function handleDrop(ev){ ev.preventDefault(); // if(dragEl.className.indexOf("uploading")>=0) return; dragEl.className="u uploading" const file = ev.dataTransfer.files[0]; const fd = new FormData(); fd.append("file",file); upload(fd) } function handleOver(ev){ ev.preventDefault(); dragEl.className="u actived" } function handleLeave(ev){ ev.preventDefault(); dragEl.className="u init" } function upload(data){ const xhr = new XMLHttpRequest(); xhr.open("POST","/upload"); xhr.responseType = "json"; const precentEl = document.getElementById("precent"); xhr.upload.onprogress=function({loaded,total}){ const precent = (loaded/total)*100; precentEl.style.transform = `translateX(-${100-precent}%)` if(precent>=100) setTimeout(() => dragEl.className="u success", 500); } xhr.onload = function(){ if(xhr.response && xhr.response.success){ setTimeout(()=>dragEl.className="u init",3000); }else{ dragEl.className="u error"; console.error(xhr.response.error); } } xhr.send(data); }

    コンソールはnode server.jsを実行し、ブラウザがアドレスを開くとプロセス全体が表示されます.