Skip to content

Instantly share code, notes, and snippets.

@iDevelopThings
Last active July 16, 2024 15:16
Show Gist options
  • Save iDevelopThings/be96aea9414cbcf17602df37b6ece0f6 to your computer and use it in GitHub Desktop.
Save iDevelopThings/be96aea9414cbcf17602df37b6ece0f6 to your computer and use it in GitHub Desktop.
Handles drag and drop file upload in VueJS
<!-- USAGE -->
<drag-drop-file-upload ref="dragDropFileUpload" @handleInput="changeImage"></drag-drop-file-upload>
//Handle image change/upload etc
changeImage({file, filePreview}) {
console.log({file, filePreview});
},
//Clear files added/dropped onto component?
this.$refs.dragDropFileUpload.clearResults();
<template>
<div>
<div class="drag-drop-upload" @dragover="handleDragOver" @dragleave="handleDragOver" @drop="handleFileSelect"
@click="clickInput" :class="{'dragging' : dragging}">
<label for="file-input" class="file-input" id="file-input-container">
<slot name="upload-container" v-if="!dragging">
Drag a file here to upload or click
</slot>
<slot name="dragging-container" v-if="dragging">
Drop files here to upload
</slot>
<input id="file-input" type="file" :accept="supportedFile" @change="handleFileInput" ref="fileInput">
</label>
</div>
<div v-if="results !== null" class="file-results">
<div v-for="(result, index) in results" >
<div class="image-preview" :style="`background-image: url('${result.filePreview}')`">
<a @click="$delete(results, index)" href="javascript:;" class="delete">
Delete
</a>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name : "DragDropFileUpload",
props : {
supportedFile : {
type : String,
default : 'image/*'
},
},
mounted()
{
},
data()
{
return {
dragging : false,
results : null,
};
},
methods : {
handleFileInput(event)
{
this.processFileInput(event.target.files);
event.target.value = '';
},
handleDragOver(event)
{
event.stopPropagation();
event.preventDefault();
this.dragging = event.type === 'dragover';
event.dataTransfer.dropEffect = 'copy';
},
handleFileSelect(event)
{
event.stopPropagation();
event.preventDefault();
this.dragging = false;
this.processFileInput(event.dataTransfer.files);
},
processFileInput(files)
{
for (let i = 0; i < files.length; i++) {
let file = files[i];
if (file.type.match('image.*')) {
let reader = new FileReader();
reader.onloadend = function () {
if (this.results === null)
this.results = [];
const results = {
filePreview : reader.result,
file : file
};
this.results.push(results);
this.$emit('handleInput', results);
}.bind(this);
reader.readAsDataURL(file);
}
}
},
clearResults() {
this.results = null;
},
clickInput()
{
this.$refs.fileInput.click();
},
}
};
</script>
<style lang="scss" scoped>
.drag-drop-upload {
width: 100%;
height: 100%;
border: 2px dashed #718096;
cursor: pointer;
padding: 1.5rem;
display: flex;
justify-content: center;
align-items: center;
border-radius: 6px;
&.dragging {
background-color: #e2e8f0;
border-color: #667eea;
}
> .file-input {
height: 100%;
pointer-events: none;
margin-bottom: 0;
font-size: 1.5rem;
color: #718096;
> input {
display: none;
}
}
}
.file-results {
display: flex;
flex-direction: column;
margin-top: 1rem;
.image-preview {
max-width: calc(100%/4);
border-radius: 0.375rem;
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06) !important;
height: 200px;
background-position: center center;
background-repeat: no-repeat;
background-size: cover;
position: relative;
overflow: hidden;
>.delete {
position: absolute;
background: #bd2130;
border-top-left-radius: 0.375rem;
color: white;
padding: 6px 10px;
bottom: 0;
right: 0;
&:hover {
background: #c82333;
}
}
}
}
</style>
@MetaMan13
Copy link

Thank you for doing this! <3

love halfamomo

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment