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/