FileInput.vue 1.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
  1. <template>
  2. <div
  3. class="file-input"
  4. :class="{ 'drag-over': isDragOver }"
  5. @click="handleClick()"
  6. @dragenter.prevent="handleDragEnter"
  7. @dragover.prevent="handleDragOver"
  8. @dragleave.prevent="handleDragLeave"
  9. @drop.prevent="handleDrop"
  10. >
  11. <slot></slot>
  12. <input
  13. class="input"
  14. type="file"
  15. name="upload"
  16. ref="inputRef"
  17. :accept="accept"
  18. @change="$event => handleChange($event)"
  19. @click.stop
  20. >
  21. </div>
  22. </template>
  23. <script lang="ts" setup>
  24. import { ref, useTemplateRef } from 'vue'
  25. withDefaults(defineProps<{
  26. accept?: string
  27. }>(), {
  28. accept: 'image/*',
  29. })
  30. const emit = defineEmits<{
  31. (event: 'change', payload: FileList): void
  32. }>()
  33. const inputRef = useTemplateRef<HTMLInputElement>('inputRef')
  34. const isDragOver = ref(false)
  35. const handleClick = () => {
  36. if (!inputRef.value) return
  37. inputRef.value.value = ''
  38. inputRef.value.click()
  39. }
  40. const handleChange = (e: Event) => {
  41. const files = (e.target as HTMLInputElement).files
  42. if (files) emit('change', files)
  43. }
  44. const handleDragEnter = () => {
  45. isDragOver.value = true
  46. }
  47. const handleDragOver = () => {
  48. isDragOver.value = true
  49. }
  50. const handleDragLeave = () => {
  51. isDragOver.value = false
  52. }
  53. const handleDrop = (e: DragEvent) => {
  54. isDragOver.value = false
  55. const files = e.dataTransfer?.files
  56. if (files && files.length > 0) {
  57. emit('change', files)
  58. }
  59. }
  60. </script>
  61. <style lang="scss" scoped>
  62. .input {
  63. display: none;
  64. }
  65. </style>