原生API实现拖拽上传文件实践

Posted Qcer

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了原生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\\/([\\s\\S]*)/.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}`);
})

效果:

以上是关于原生API实现拖拽上传文件实践的主要内容,如果未能解决你的问题,请参考以下文章

拖拽上传功能

ajax上传文件及进度显示

原生JS实现图标图片拖拽

selenium怎么实现文件拖拽上传功能

怎么用jsp实现拖拽上传图片?

拖拽上传文件