You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

120 lines
2.8 KiB
Vue

<template>
<div @dragover.prevent @drop.prevent>
<div class="drop" @drop="dragFile">
<span v-if="loading" class="loading">
Loading...
</span>
<span v-else>
Drag file here
</span>
<img ref="thumb" />
</div>
</div>
</template>
<script setup>
import {ref, computed} from 'vue'
const emit = defineEmits(['upload'])
const file = ref([])
const fileType = ref("")
const thumb = ref(null)
const loading = ref(false)
const dragFile = (e) => {
file.value = e.dataTransfer.files[0]
createPreview(file.value)
}
const container = computed(()=>{
if (fileType.value == 'image') return 'img'
if (fileType.value == 'video') return 'video'
return 'div'
})
const createPreview = (file) => {
let fileExt;
const fileName = file.name
const filePath = (window.URL || window.webkitURL).createObjectURL(file)
// get file extension
fileExt = fileName.toLowerCase().substr(fileName.lastIndexOf('.')+1, fileName.length - fileName.lastIndexOf('.'))
// get file type
fileType.value = file.type.toLowerCase().substr(0, file.type.indexOf("/"))
const reader = new FileReader()
reader.readAsDataURL(file)
loading.value = true
reader.onloadend = (e) => {
if (e.target.readyState == FileReader.DONE) {
if (fileType.value == 'video') videoSnapshot(filePath)
if (fileType.value == 'image') imageSnapshot(filePath)
}
}
}
const imageSnapshot = (url) => {
thumb.value.src = url
emit('upload', url)
loading.value = false;
}
const videoSnapshot = (url) => {
let video = document.createElement('video')
video.src = url
const snapshot = () => {
let canvas = document.createElement('canvas')
canvas.width = 1280
canvas.height = 720
let ctx = canvas.getContext('2d')
ctx.drawImage(video, 0, 0, canvas.width, canvas.height)
thumb.value.src = canvas.toDataURL('image/png')
emit('upload', thumb.value.src)
loading.value = false
video.removeEventListener('canplay', snapshot)
}
video.addEventListener('canplay', snapshot)
}
</script>
<style>
.drop {
position: relative;
display: inline-block;
width: 160px;
height: 90px;
border: 1px solid currentColor;
padding: 16px;
}
.drop img,
.drop video {
position: absolute;
z-index: 100;
top: 0;
left: 0;
width: 100%;
height: 100%;
object-fit: cover;
pointer-events: none;
}
.loading {
opacity: 0.5;
}
</style>