vue3实现全屏拖拽上传文件带进度条

拖拽 api,这个是 html5 新增的一个 api,给一个元素设置 draggable = true 属性时,该元素就会支持拖拽拖拽元素事件如下

拖拽 api,这个是 html5 新增的一个 api,给一个元素设置 draggable = true 属性时,该元素就会支持拖拽拖拽元素事件如下

1. ondrag 当拖动元素的时候运行脚本
2. ondragstart 当拖动操作开始时候运行脚本
3. ondragend 当拖动操作结束的时候运行脚本

目标元素的事件如下

1. ondragover 当元素被拖动至有效拖放目标上方时执行脚本
2. ondragenter 当元素被拖动至有效拖动目标时执行脚本
3. ondragleave 当元素离开至有效拖放目标是运行脚本
4. ondrop 当被拖动元素正在被放下的时候运行脚本

具体代码如下

<template>
    <div class="mask" v-show="show" id="mask">
        <h3>拖拽到这里上传</h3>
    </div>
    <div class="upload-progress" v-if="fileList.length > 0">
        <div class="item" v-for="item in fileList">
            <div class="item-name">{{ item.name }}</div>
            <div class="item-progress">
                <a-progress :percent="item.percentage" :status="item.status" />
            </div>
        </div>
    </div>
</template>
<script lang="ts" setup>
import { ref, reactive, onMounted } from 'vue'
import axios from 'axios';
const show = ref<boolean>(false) // 是否展示遮罩
const fileList = ref<any>([]) // 文件列表
const accept = ref<string>('.jpg,.gif,.png,.jpeg');
const uploadSetting = reactive({
    action: '#',//上传地址
    autoUpload: false,//是否自动上传
});
let tempIndex = 0 // 做一个标记
onMounted(() => {
    disableDefaultEvents()
    init()
})
// 初始化拖入事件
const init = () => {
    const ele = document.querySelector('body')
    if (ele) {
        ele.addEventListener('dragenter', () => {
            show.value = true
        }) //拖后放
        ele.addEventListener('dragleave', (e: any) => {
            if (
                e.target.nodeName === 'HTML' ||
                e.target === e.explicitOriginalTarget ||
                (!e.fromElement &&
                    (e.clientX <= 0 ||
                        e.clientY <= 0 ||
                        e.clientX >= window.innerWidth ||
                        e.clientY >= window.innerHeight))
            ) {
                show.value = false
            }
        }) //拖离
        ele.addEventListener('drop', (e) => {
            show.value = false
            e.preventDefault()
            onDrop(e)
        }) //拖进
    }
}
// 禁用默认拖拽事件
const disableDefaultEvents = () => {
    const doc = document.documentElement
    doc.addEventListener('dragleave', (e) => e.preventDefault()) //拖离
    doc.addEventListener('drop', (e) => e.preventDefault()) //拖后放
    doc.addEventListener('dragenter', (e) => e.preventDefault()) //拖进
    doc.addEventListener('dragover', (e) => e.preventDefault()) //拖来拖去
}
// 拖入时的事件
const onDrop = (e: any) => {
    if (e.dataTransfer) {
        const list = [].slice.call(e.dataTransfer.files).filter((file) => {
            if (accept) {
                return checkType(file, accept)
            }
            return true
        })
        fileList = list.map((p) => {
            return handleStart(p)
        })
        onChange()
        if (uploadSetting.autoUpload) {
            if (uploadSetting.action === '') {
                throw 'need action'
                return
            }
            list.forEach((file: any) => {
                uploadPost(file)
            })
        }
    }
}
// 检查文件类型
const checkType = (file: any, accept = '') => {
    const { type, name } = file
    if (accept.length === 0) return true
    const extension = name.indexOf('.') > -1 ? `.${name.split('.').pop()}` : ''
    const baseType = type.replace(/\/.*$/, '')
    return accept
        .split(',')
        .map((type) => type.trim())
        .filter((type) => type)
        .some((acceptedType) => {
            if (/\..+$/.test(acceptedType)) {
                return extension === acceptedType
            }
            if (/\/\*$/.test(acceptedType)) {
                return baseType === acceptedType.replace(/\/\*$/, '')
            }
            if (/^[^/]+\/[^/]+$/.test(acceptedType)) {
                return type === acceptedType
            }
        })
}
// 处理文件列表返回值
const handleStart = (rawFile: any) => {
    rawFile.uid = Date.now() + tempIndex++
    return {
        status: 'ready',
        name: rawFile.name,
        size: rawFile.size,
        percentage: 0,
        uid: rawFile.uid,
        raw: rawFile,
    }
}

//文件上传方法
const uploadPost = (rawFile: any) => {
    const formData = new FormData()
    formData.append('files', rawFile.raw)
    return axios({
        method: 'POST',
        url: uploadAction,
        data: formData,
        headers: { "authorization": localStorage.getItem(accessToken) },
        onUploadProgress: function (progressEvent) {
            // 对原生进度事件的处理
            // progressEvent.loaded:已上传文件大小
            // progressEvent.total:被上传文件的总大小
            rawFile.percentage = Number(
                ((progressEvent.loaded / progressEvent.total) * 90).toFixed(2)
            );
        },
    }).then((res) => {
        console.log(res);
    }).catch((err) => {
        console.log(err);
        message.error(rawFile.name + '上传失败');
        rawFile.percentage = 100
        rawFile.status = 'exception';
        setTimeout(function () {
            fileList.value = fileList.value.filter((item: any) => item.uid !== rawFile.uid);
        }, 1000)
    });
}
</script>
<style lang="scss" scoped>
.mask {
    top: 0;
    bottom: 0;
    right: 0;
    left: 0;
    position: fixed;
    z-index: 9999;
    opacity: 0.6;
    text-align: center;
    background: #000;

    h3 {
        margin: -0.5em 0 0;
        position: absolute;
        top: 50%;
        left: 0;
        right: 0;
        -webkit-transform: translateY(-50%);
        -ms-transform: translateY(-50%);
        transform: translateY(-50%);
        font-size: 40px;
        color: #fff;
        padding: 0;
    }
}

.upload-progress {
    position: fixed;
    background-color: #fff;
    right: 0;
    bottom: 0;
    z-index: 9999;
    box-shadow: 0 1px 4px rgb(0 21 41 / 8%);
    width: 500px;
    height: auto;
    padding: 10px 21px;

    .item {
        display: flex;
        border-bottom: 1px solid #f0f0f0;
        padding: 12px 0;
        justify-content: space-between;

        .item-name {
            width: 30%;
        }

        .item-progress {
            width: 67%;
        }
    }
}
</style>

灵感来自:来写一个基于Vue3的全屏拖拽上传组件吧啊🎃 – 掘金 (juejin.cn)

以上这篇vue3实现全屏拖拽上传文件带进度条就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持芦苇派。

原创文章,作者:ECHO陈文,如若转载,请注明出处:https://www.luweipai.cn/html/1658906633/