zoukankan      html  css  js  c++  java
  • 原生API实现拖拽上传文件实践

    功能:

    拖拽上传文件、图片,上传的进度条,能够同时上传多个文件。

    完整的demo地址:https://github.com/qcer/FE-Components/tree/master/QDrag

    涉及到的API:

    1、HTML5的拖拽事件:dragenter,dragover,drop等

    2、XMLHttpRequest  Level2

    3、FormData

    4、(扩展:HTML5的File API)

    概述:

    1、利用拖拽实践的API将一个普通的div自定义成一个放置目标,这里有一个技巧是放置一个隐藏的input[type='file']的元素,在div上绑定input的点击事件,再点击事件中触发input的click事件,能够在div上任意位置达到type=file选择文件上传的效果。

    2、在div的drag事件中获取文件对象,通过FormData对象构造表单序列化的数据,同时动态生成页面元素,通过XMLHttpRequest对象发送数据,在xhr.upload的progress事件中实现上传进度的功能。

    3、后端通过nodejs实现一个http服务器,接受数据,进而可以扩展的解析数据。

    前端页面代码:

    <!DOCTYPE html>
    <html>
    <head>
        <title></title>
        <style type="text/css">
            #qdrag{
                height: 300px;
                width: 100%;
                background: #eee;
                border-radius: 5px;
                padding-top: 20px;
            }
            #qdrag-hidden {
                display: none;
                position: absolute;
                z-index: 10;
            }
            #qdrag .qdragzone{
                width: 100%;
                height: 50px;
                background: #ccc;
                line-height: 50px;
                border-bottom: 2px solid #fff;
                border-radius: 2px;
                overflow: hidden;
            }
    
            #qdrag .qdragzone img{
                margin-top: 9px;
                margin-left: 2%;
                margin-right: 4%;
                float: left;
            }
            #qdrag .qdragzone span{
                display: inline-block;
                font-weight: bold;
                font-size: 14px;
                float: left;
                width: 20%;
                color: #339966;
                font-family: "Times New Roman", Times, serif;
                 /*font-family:Arial,Helvetica,sans-serif;font-size:100%;*/
            }
            #qdrag .qdragzone progress{
                border-radius: 6px;
                height: 12px;
                width: 250px;
                color: #5cb85c;
                background:#fff;
            }
            progress::-moz-progress-bar { background: #fff;border-radius: 6px; }
            progress::-webkit-progress-bar { background: #fff;border-radius: 6px;}
    
            progress::-webkit-progress-value {background-color:#5cb85c;border-radius: 6px;}
            progress::-moz-progress-value { background-color:#5cb85c;border-radius: 6px;}
            }
        </style>
    </head>
    <body>
    
        <div id="qdrag">
            <input type="file" id="qdrag-hidden" name="image" value=""></input>
            <div class="qdragzone">
                <img src="./public/upload.png">
                <span>Name:test.txt</span>
                <span>Size:00000 Byte</span>
                <progress value="0.2" max="1">
            </div>
        </div>
        <script type="text/javascript">
            var qdrag = document.getElementById('qdrag');
            var qdrag_hidden = document.getElementById('qdrag-hidden');
            qdrag.onclick = function () { qdrag_hidden.click();}
            qdrag_hidden.onchange = function () {
                // body...
                var fileList = this.files;
                for (var i = 0; i < fileList.length; i++) {
                    sendFileByXHR('./upload.html',fileList[i]);
                }
            }
    
            function sendFileByXHR(url,fielObj) {
                // body...
                var xhr = new XMLHttpRequest();
                var newprogress = createTagsEle(fielObj).newprogress;
                xhr.upload.onprogress = function (event) {
                    // body...
                    console.log('xhr-loaded:'+event.loaded);
                    newprogress.setAttribute('value',event.loaded/event.total);
                }
                xhr.onreadystatechange = function () {
                    // body...
                    if (xhr.status === 200 && xhr.readyState === 4) {
                        console.log(xhr.responseText);
                    }
                }
                xhr.onabort = function (event) {
                    // body...
                    console.log('abort');
                }
                xhr.onerror = function (event) {
                    // body...
                    console.log('error');
                }
                var data = new FormData();
                data.append(fielObj.name,fielObj);
                xhr.open('POST',url,true);
                xhr.send(data);
    
            }
            function createTagsEle(fileObj) {
                // body...
                //create
                var fragment = document.createDocumentFragment();
                var newdiv = document.createElement('div');
                var newimg = document.createElement('img');
                var newspanName = document.createElement('span');
                var newspanSize = document.createElement('span');
                var newprogress = document.createElement('progress');
    
                //set attribute
                newdiv.setAttribute('class','qdragzone');
                newimg.setAttribute('src','./public/upload.png')
                newspanName.innerHTML = 'Name: ' + fileObj.name;
                newspanSize.innerHTML = 'Size: ' + fileObj.size+' Byte';
                newprogress.setAttribute('value',0);
                newprogress.setAttribute('max',1);
    
                //append
                fragment.appendChild(newdiv);
                newdiv.appendChild(newimg);
                newdiv.appendChild(newspanName);
                newdiv.appendChild(newspanSize);
                newdiv.appendChild(newprogress);
    
                // append to DOM
                qdrag.appendChild(fragment);
                return {newprogress};
            }
    
            qdrag.addEventListener('dragover',function (event) {
                // body...
                event.preventDefault();
            });
            qdrag.addEventListener('dragenter',function (event) {
                // body...
                event.preventDefault();
            });
            qdrag.addEventListener('drop',function (event) {
                // body...
                event.preventDefault();
                var fileList = Array.from(event.dataTransfer.files);
                for (var i = 0; i < fileList.length; i++) {
                    sendFileByXHR('./upload.html',fileList[i]);
                }
            });
            
        </script>
    </body>
    </html>

    后端代码:

    var http = require('http');
    var fs = require('fs')
    const PORT = 44444;
    const MIME = {
        default:'text/plain',
        html:'text/html',
        css:'text/css',
        js:'text/javascript',
        png:'image/png',
        jpg:'image/jpg',
        jpeg:'image/jpeg',
        json:'application/json',
        from:'multipart/form-data'
    }
    
    function handleStaticResource(req,res) {
        // body...
        var param = req.url.replace('/public','');
        var staticResource = fs.readFileSync('.'+param,'utf8');
    
        var fileType = req.url.split('/').pop().split('.').pop();
        switch(true){
            case ['js','css'].includes(fileType):
                res.setHeader('Content-Type',MIME[fileType]);
                break;
            case ['png','jpg','jpeg'].includes(fileType):
                staticResource = new Buffer(fs.readFileSync('.'+param,'base64'),'base64');
                console.log(fileType);
                res.setHeader('Content-Type',MIME[fileType]);
                break;
            default :
                res.setHeader('Content-Type',MIME['default']);
                console.log(MIME['default']);
                break;
        }
        res.end(staticResource);
    }
    
    var router = function (req,res) {
        // body...
        res.render = function (path,options) {
            // body...
            var content_html = fs.readFileSync(path,'utf8');
            res.writeHead(200,{'Content-Type':MIME['html']});
            res.end(new Buffer(content_html,'utf8'));
        }
    
        switch(true){
            case /^/public/([sS]*)/.test(req.url):
                handleStaticResource(req,res);
                break;
            case req.url === '/':
                // console.log(req.url);
                res.render('./testdrag.html');
                break;
            case req.url === '/upload.html':
                // console.log(req.headers);
                var buffers = [];
                req.on('data',function (chunk) {
                    // body...
                    buffers.push(chunk);
                })
                req.on('end',function () {
                    // body...
                    var data = Buffer.concat(buffers).toString();
                    res.end("ok");//正确的调用位置
                })
                // res.end('currSize:' + buffers.length +'  '+ (new Date()).toGMTString());//错误的调用位置
                break;
            default:
                // console.log(req.url);
                res.end();
        };
    }
    
    var server  = http.createServer(router);
    server.listen(PORT,function () {
        // body...
        console.log(`the server is linstening on port ${PORT}`);
    })

    效果:

  • 相关阅读:
    bzoj2733 永无乡 平衡树按秩合并
    bzoj2752 高速公路 线段树
    bzoj1052 覆盖问题 二分答案 dfs
    bzoj1584 打扫卫生 dp
    bzoj1854 游戏 二分图
    bzoj3316 JC loves Mkk 二分答案 单调队列
    bzoj3643 Phi的反函数 数学 搜索
    有一种恐怖,叫大爆搜
    BZOJ3566 概率充电器 概率dp
    一些奇奇怪怪的过题思路
  • 原文地址:https://www.cnblogs.com/qcblog/p/7142660.html
Copyright © 2011-2022 走看看