文件拖拽上傳功能現(xiàn)在已經(jīng)隨處可見,大家應(yīng)該都用過了吧,那么它具體是怎么實(shí)現(xiàn)的大家有去了解過嗎?今天我們一起來實(shí)現(xiàn)一下這個功能,并封裝一個拖拽上傳組件吧。
效果展示
體驗(yàn)地址:http://jyeontu.xyz/jvuewheel/#/JDragUploadView
功能實(shí)現(xiàn)
原生JavaScrip實(shí)現(xiàn)
首先我們應(yīng)該先將頁面寫好:
<!DOCTYPE html>
<html lang="en">
<head>
<title>點(diǎn)擊或拖拽上傳并顯示圖片</title>
<style>
body {
display: flex;
flex-direction: column;
}
h1 {
text-align: center;
}
#drop-zone {
width: 300px;
height: 200px;
border: 2px dashed #ccc;
margin: 20px auto;
text-align: center;
line-height: 200px;
font-size: 18px;
}
#uploaded-image {
max-width: 300px;
max-height: 300px;
margin: 20px auto;
}
</style>
</head>
<body>
<h1>點(diǎn)擊或拖拽上傳并顯示圖片示例</h1>
<div id="drop-zone">點(diǎn)擊或拖拽上傳圖片</div>
<img id="uploaded-image" src="" alt="上傳的圖片" />
<script>
</script>
</body>
</html>
我們試下直接拖拽圖片到頁面上是什么效果
我們發(fā)現(xiàn)直接將圖片拖拽到頁面上會在新頁面打開圖片,那么我們需要阻止這一個默認(rèn)行為以允許放置,頁面的拖拽行為主要會觸發(fā)以下幾個事件:
dragenter
dragenter
事件在可拖動的元素或者被選擇的文本進(jìn)入一個有效的放置目標(biāo)時觸發(fā)。
目標(biāo)對象是用戶直接選擇的范圍(由用戶直接指示作為放置目標(biāo)的元素),或者 <body>
元素。
dragleave
dragleave
事件在拖動的元素或選中的文本離開一個有效的放置目標(biāo)時被觸發(fā)。
此事件不可取消。
dragover
dragover
事件在可拖動的元素或者被選擇的文本被拖進(jìn)一個有效的放置目標(biāo)時(每幾百毫秒)觸發(fā)。
該事件在放置目標(biāo)上觸發(fā)。
drop
drag
事件在用戶拖動元素或選擇的文本時,每隔幾百毫秒就會被觸發(fā)一次。
效果實(shí)現(xiàn)
獲取上傳框和預(yù)覽框元素
const dropZone = document.getElementById("drop-zone");
const uploadedImage = document.getElementById("uploaded-image");
圖片進(jìn)入上傳框時,為上傳框加一層灰色蒙層
監(jiān)聽上傳框的dragenter
事件,在圖片移動進(jìn)入上傳框時改變上傳框的背景顏色。
dropZone.addEventListener("dragenter", function (event) {
dropZone.style.backgroundColor = "#f7f7f7";
});
圖片離開上傳框時,去除上傳框的灰色蒙層
監(jiān)聽上傳框的dragleave
事件,在圖片移出上傳框時去除上傳框的背景顏色。
dropZone.addEventListener("dragleave", function (event) {
dropZone.style.backgroundColor = "";
});
阻止瀏覽器默認(rèn)行為,例如打開文件
dragover
和drop
事件都會觸發(fā)瀏覽器打開文件,我們需要阻止其默認(rèn)行為。
dropZone.addEventListener("dragover", function (event) {
event.preventDefault();
});
dropZone.addEventListener("drop", function (event) {
event.preventDefault();
});
獲取拖拽上傳的文件
拖拽釋放會觸發(fā)drop
事件,我們只需要監(jiān)聽drop
事件,獲取到拖拽的文件列表event.dataTransfer.files
即可。
dropZone.addEventListener("drop", function (event) {
event.preventDefault();
dropZone.style.backgroundColor = "";
const file = event.dataTransfer.files[0];
handleFile(file);
});
處理上傳文件,為圖片時設(shè)置預(yù)覽圖
判斷上傳的文件是否為圖片,我們只需要判斷上傳文件的type是否為image
開頭,是的話我們可以將其轉(zhuǎn)為dataUrl文件并設(shè)置預(yù)覽。
function handleFile(file) {
if (file && file.type.startsWith("image/")) {
const reader = new FileReader();
reader.onload = function (event) {
uploadedImage.src = event.target.result;
};
reader.readAsDataURL(file);
}
}
封裝為vue組件
知道了原生js實(shí)現(xiàn)一個拖拽上傳功能之后,我們也能很容易得將其封裝成一個vue組件。
監(jiān)聽拖拽事件
在vue中,我們直接通過@dragover
、@dragleave
、@drop
即可監(jiān)聽元素的拖拽事件。
<div
class="upload-area"
@dragover.prevent="handleDragOver"
@dragleave="handleDragLeave"
@drop.prevent="handledrop"
@click="handleUploadClick"
>
<p v-if="!isDragging" class="tip-text">{{ tipText }}</p>
<p v-else>{{ tipConfirmText }}</p>
</div>
事件的處理邏輯和原生js其實(shí)都是一樣的。
methods: {
handleDragOver(event) {
event.preventDefault();
this.isDragging = true;
},
handleDragLeave() {
this.isDragging = false;
},
handledrop(event) {
event.preventDefault();
this.isDragging = false;
const file = event.dataTransfer.files[0];
this.uploadFile(file);
}
}
獲取到上傳文件并傳遞給父組件
獲取到上傳的文件后,我們不應(yīng)該組件內(nèi)直接處理文件了,將其傳遞給父組件進(jìn)行處理即可。
uploadFile(file) {
this.$emit("uploadFile", file);
}
組件完整代碼
功能邏輯與原生JavaScrip基本相同,這里也不重復(fù)描述了,直接看代碼吧:
<template>
<div class="drag-upload">
<div
class="upload-area"
@dragover.prevent="handleDragOver"
@dragleave="handleDragLeave"
@drop.prevent="handledrop"
@click="handleUploadClick"
>
<p v-if="!isDragging" class="tip-text">{{ tipText }}</p>
<p v-else>{{ tipConfirmText }}</p>
</div>
<input
type="file"
ref="fileInput"
style="display: none"
@change="handleFileselected"
/>
</div>
</template>
<script>
export default {
name: "JDragUpload",
props: {
tipText: {
type: String,
default: "將文件拖放到此處或點(diǎn)擊上傳",
},
tipConfirmText: {
type: String,
default: "釋放文件以上傳",
},
},
data() {
return {
isDragging: false,
};
},
methods: {
handleDragOver(event) {
event.preventDefault();
this.isDragging = true;
},
handleDragLeave() {
this.isDragging = false;
},
handledrop(event) {
event.preventDefault();
this.isDragging = false;
const file = event.dataTransfer.files[0];
this.uploadFile(file);
},
handleUploadClick() {
this.$refs.fileInput.click();
},
handleFileselected() {
const file = this.$refs.fileInput.files[0];
this.uploadFile(file);
},
uploadFile(file) {
this.$emit("uploadFile", file);
},
},
};
</script>
<style lang="less" scoped>
.drag-upload {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
width: 100%;
border: 2px dashed #ccc;
.upload-area {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
width: 100%;
background-color: #f0f0f0;
cursor: pointer;
.tip-text {
text-align: center;
}
}
}
</style>
源碼
組件體驗(yàn)及文檔地址:http://jyeontu.xyz/jvuewheel/#/JDragUploadView
Gitee源碼:https://gitee.com/zheng_yongtao/jyeontu-component-warehouse/tree/master/JYeontuComponentWarehouse/packages/JDragUpload
該文章在 2023/10/30 11:09:45 編輯過