h5拖拽文件

1、功能、需求

实现拖拽上传,要求可以拖拽单文件、夹文件,多文件,及同时拖拽文件和文件夹,如果拖拽了文件夹要遍历文件下所有文件及子文件夹的文件

2、实现效果、流程图

2.1先看效果

20210211014819527.gif

2.2流程图

ec093157d9ef548d1ea11fa4dc28ee31.jpg

3、代码

注意事项
调试需要使用HTTP协议打开文件,如果使用本地协议调试将无法获取到拖拽的内容

3.1添加监听事件

假设页面中存在一个ID为dropBox的div,给这个div添加拖拽事件,
其中dragoverdrop事件是必须的,需要在dragover中取消浏览器默认事件才能实现文件拖拽

    let dropBox = document.getElementById("dropBox")
    //监听文件拖拽移入(必须)
    dropBox.addEventListener('dragover', FileDragHover, false)
    //监听文件拖拽移出
    dropBox.addEventListener('dragleave', FileDragLeave, false)
    //监听文件拖拽放下(必须)
    dropBox.addEventListener('drop', Drop, false)

3.2事件处理

//处理文件拖入事件
function FileDragHover(e) {
   e.stopPropagation();
   e.preventDefault();
   //添加类名修改样式
   e.target.classList.add("dropBoxHover")
   e.target.innerText = "松开鼠标上传"
}
//处理拖拽离开事件
function FileDragLeave(e) {
   e.stopPropagation();
   e.preventDefault();
   //移除类名修改样式
   e.target.classList.remove("dropBoxHover")
   e.target.innerText = "拖拽文件上传"
}
//处理文件拖拽放下事件
async function Drop(e) {

        //阻止事件冒泡
        e.stopPropagation();
        //阻止事件的默认行为
        e.preventDefault();
        //储存获取到的文件列表
        let fileList = [];
        let DirectoryEntryList = [];
        //清除样式
        e.target.classList.remove("dropBoxHover")

        if (e.dataTransfer.items) {
            // 拖拽对象列表转换成数组
            let items = new Array(...e.dataTransfer.items);
            // 获得DirectoryEntry对象列表
            for (let index = 0; index < items.length; index++) {
                let e = items[index];
                let item = null;
                //兼容不同内核的浏览器
                if (e.webkitGetAsEntry) {
                    item = e.webkitGetAsEntry();
                } else if (e.getAsEntry) {
                    item = e.getAsEntry();
                } else {
                    this.$alert("浏览器不支持拖拽上传", "提示");
                    return;
                }
                DirectoryEntryList.push(item);
            }
            if (DirectoryEntryList.length > 0) {
                for (let index = 0; index < DirectoryEntryList.length; index++) {
                    let item = DirectoryEntryList[index];
                    if (item) {
                        //获取文件夹目录
                        let FileTree = await getFileTree(item);
                        // 拿到目录下的所有文件
                        if (Array.isArray(FileTree)) {
                            //展平文件夹
                            flattenArray(FileTree, fileList);
                        } else {
                            //方便后续处理,单文件时也包装成数组
                            fileList.push(FileTree);
                        }
                    }
                }
            }
        }
        console.log(fileList);
    }

3.3异步方法封装处理

由于获取文件对象、获取目录文件等方法是异步的,结果要用回到函数的方式获取,非常不利于文件夹的递归操作,因此这里把异步的方法做了promise封装,调用方法返回一个promise对象,以便使用await 以同步的方式获得结果,以便于递归操作

    /**
     * 获取文件
     */
    function fileSync(item) {
        return new Promise((resolve, reject) => {
            item.file(res => {
                resolve(res);
            });
        });
    }
    //读取文件夹下的文件
    function readEntriesSync(dirReader) {
        return new Promise((rel, rej) => {
            dirReader.readEntries(res => {
                rel(res);
            });
        });
    }
    /**
     * 获取文件目录结构树
     *
     */
    async function getFileTree(item) {
        let that = this;
        var path = item.fullPath || "";
        let dir = new Array();
        if (item.isFile) {
            let resFile = await this.fileSync(item);
            resFile.path = path;
            return resFile;
            // item为文件夹时
        } else if (item.isDirectory) {
            var dirReader = item.createReader();
            let entries = await that.readEntriesSync(dirReader);
            for (let i = 0; i < entries.length; i++) {
                let proItem = await that.getFileTree(entries[i]);
                dir.push(proItem);
            }
            return dir;
        }
    }

3.4完整代码


<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        .dropBox {
            width: 50%;
            height: 200px;
            margin: 150px auto;
            border-radius: 10px;
            display: flex;
            justify-content: center;
            align-items: center;
            border: dashed 2px rgb(212, 212, 212);
            color: rgb(148, 148, 148);
        }

        .dropBoxHover {
            border-color: rgb(0, 195, 255);
            box-shadow: 0 0px 8px rgba(0, 0, 0, 0.1) inset,
                0 0px 3px rgba(0, 0, 0, .5) inset,
                0 0px 5px rgba(0, 0, 0, .3) inset;
            /* color:  rgb(0, 195, 255); */
        }
    </style>

</head>

<body>
    <p>用http协议打开,效果请看控制台</p>
    <div class="dropBox" id="dropBox">
        拖拽文件上传
    </div>
</body>

<script>
    let dropBox = document.getElementById("dropBox")
    //监听文件拖拽移入
    dropBox.addEventListener('dragover', FileDragHover, false)
    //监听文件拖拽移出
    dropBox.addEventListener('dragleave', FileDragLeave, false)
    //监听文件拖拽放下
    dropBox.addEventListener('drop', Drop, false)

    function FileDragHover(e) {
        e.stopPropagation();
        e.preventDefault();
        e.target.classList.add("dropBoxHover")
        e.target.innerText = "松开鼠标上传"
    }
    function FileDragLeave(e) {
        e.stopPropagation();
        e.preventDefault();
        e.target.classList.remove("dropBoxHover")
        e.target.innerText = "拖拽文件上传"
    }
    async function Drop(e) {

        //阻止事件冒泡
        e.stopPropagation();
        //阻止事件的默认行为
        e.preventDefault();
        //储存获取到的文件列表
        let fileList = [];
        let DirectoryEntryList = [];
        //清除样式
        e.target.classList.remove("dropBoxHover")

        if (e.dataTransfer.items) {
            // 拖拽对象列表转换成数组
            let items = new Array(...e.dataTransfer.items);
            // 获得DirectoryEntry对象列表
            for (let index = 0; index < items.length; index++) {
                let e = items[index];
                let item = null;
                //兼容不同内核的浏览器
                if (e.webkitGetAsEntry) {
                    item = e.webkitGetAsEntry();
                } else if (e.getAsEntry) {
                    item = e.getAsEntry();
                } else {
                    this.$alert("浏览器不支持拖拽上传", "提示");
                    return;
                }
                DirectoryEntryList.push(item);
            }
            if (DirectoryEntryList.length > 0) {
                for (let index = 0; index < DirectoryEntryList.length; index++) {
                    let item = DirectoryEntryList[index];
                    if (item) {
                        //获取文件夹目录
                        let FileTree = await getFileTree(item);
                        // 拿到目录下的所有文件
                        if (Array.isArray(FileTree)) {
                            //展平文件夹
                            flattenArray(FileTree, fileList);
                        } else {
                            //方便后续处理,单文件时也包装成数组
                            fileList.push(FileTree);
                        }
                    }
                }
            }
        }
        console.log(fileList);
    }

    /**
     * 获取文件
     */
    function fileSync(item) {
        return new Promise((resolve, reject) => {
            item.file(res => {
                resolve(res);
            });
        });
    }

    //读取文件夹下的文件
    function readEntriesSync(dirReader) {
        return new Promise((rel, rej) => {
            dirReader.readEntries(res => {
                rel(res);
            });
        });
    }

    /**
     * 展平数组
     * @param {Array} 需要展平的数组
     * @param {Array} 展平后的数组
     *
     */
    function flattenArray(array, result) {
        // console.log(array, flatArray);
        for (let i = 0; i < array.length; i++) {
            if (Array.isArray(array[i])) {
                this.flattenArray(array[i], result);
            } else {
                result.push(array[i]);
            }
        }
    }

    /**
     * 获取文件目录结构树
     *
     */
    async function getFileTree(item) {
        let that = this;
        var path = item.fullPath || "";
        let dir = new Array();
        if (item.isFile) {
            let resFile = await this.fileSync(item);
            resFile.path = path;
            return resFile;
            // item为文件夹时
        } else if (item.isDirectory) {
            var dirReader = item.createReader();
            let entries = await that.readEntriesSync(dirReader);
            for (let i = 0; i < entries.length; i++) {
                let proItem = await that.getFileTree(entries[i]);
                dir.push(proItem);
            }
            return dir;
        }
    }


</script>

</html>

留言板:

0/500

0条留言

还没有留言哦,抢个沙发吧!