Skip to content

Instantly share code, notes, and snippets.

@daliborgogic
Last active October 6, 2023 13:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save daliborgogic/f2709d6923f1103b0e0dcaeac87c6fee to your computer and use it in GitHub Desktop.
Save daliborgogic/f2709d6923f1103b0e0dcaeac87c6fee to your computer and use it in GitHub Desktop.
Input type file component with drag and drop (Vue.js)
<template>
<div ref="div">
<label>
<strong v-if="progress === 0">
{{ label }}
<svg width="24" height="24" viewBox="0 0 24 24"><path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/><path d="M0 0h24v24H0z" fill="none"/></svg>
</strong>
<strong v-if="progress > 0 && progress < 100"> {{ progress }}%</strong>
<span v-else>{{ name }}</span>
<input ref="input" type="file" :accept="accept" @change="onFileChange"/>
</label>
<svg v-if="progress === 100" @click="removeFile" width="24" height="24" viewBox="0 0 24 24">
<path d="M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z"></path>
<path d="M0 0h24v24H0z" fill="none"></path>
</svg>
<pre>{{ error }}</pre>
</div>
</template>
<script>
export default {
props: {
label: {
type: String,
default: 'Drag and Drop'
},
accept: {
type: String,
default: '*' // image/png, image/jpeg, application/pdf, application/vnd.ms-excel
}
},
data () {
return {
file: null,
name: null,
progress: 0,
error: null,
dragAndDropCapable: true
}
},
mounted () {
const { div } = this.$refs
// Determine if drag and drop functionality is capable in the browser
this.dragAndDropCapable = this.isDragAndDropCapable()
if(this.dragAndDropCapable) {
['drag', 'dragstart', 'dragend', 'dragover', 'dragenter', 'dragleave', 'drop'].forEach( event => {
document.body.addEventListener(event, e => {
e.preventDefault()
e.stopPropagation()
// if (e.type === 'dragover') {
// console.log('dragover', div) // eslint-disable-line
// div.classList.add('dragover')
// }
})
})
div.addEventListener('drop', e => {
this.onFileChange(e)
})
}
},
methods: {
isDragAndDropCapable () {
const { div } = this.$refs
return (('draggable' in div)
|| ('ondragstart' in div && 'ondrop' in div))
&& 'FormData' in window
&& 'FileReader' in window
},
onFileChange(e) {
// e.preventDefault()
const files = e.target.files || e.dataTransfer.files
if (!files.length)
return
this.createFile(files[0])
},
createFile(file) {
const reader = new FileReader()
const vm = this
reader.onprogress = e => {
if (e.lengthComputable) {
vm.trackProgress(e.loaded, e.total)
}
}
reader.onloadend = e => {
const { error } = e.target
if (error != null) {
switch (error.code) {
case error.ENCODING_ERR:
vm.error = 'Encoding error!'
break
case error.NOT_FOUND_ERR:
vm.error = 'File not found!'
break
case error.NOT_READABLE_ERR:
vm.error = 'File could not be read!'
break
case error.SECURITY_ERR:
vm.error = 'Security issue with file!'
break
default:
vm.error = 'I have no idea what\'s wrong!'
}
}
vm.trackProgress(e.loaded, e.total)
}
reader.onload = e => {
const { result } = e.target
vm.file = result
// this.$emit('load', result)
vm.name = file.name
}
reader.readAsBinaryString(file)
},
trackProgress (loaded, total) {
this.progress = parseInt(((loaded / total) * 100), 10)
},
removeFile () {
this.progress = 0
this.file = ''
this.name = null
// this.$emit('load', null)
}
}
}
</script>
<style scoped>
input[type="file"] {
display: none;
}
strong,
svg {
vertical-align: middle;
}
</style>
@daliborgogic
Copy link
Author

daliborgogic commented Sep 26, 2018

vue-drag-drop

$ vue serve -o InputTypeFile.vue
  • handle errors
  • UI for non capable browsers

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