dragUpload.vue 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. <template>
  2. <div tabindex="0" :class="['drag', { 'drag-active': active }]" ref="upload">
  3. <el-icon size="52" color="#2260FF">
  4. <UploadFilled />
  5. </el-icon>
  6. <p class="drag-subtile">
  7. 支持点击/粘贴/拖拽到此区域上传
  8. <br />
  9. 单个文件夹最大支持10M
  10. </p>
  11. <input ref="fileIpt" class="filePaste-ipt" />
  12. <input class="file-ipt" type="file" :accept="accept" multiple @change="changeFile" />
  13. </div>
  14. </template>
  15. <script setup>
  16. import { ref, onMounted, onUnmounted } from 'vue'
  17. import { UploadFilled } from '@element-plus/icons-vue'
  18. const upload = ref(null)
  19. const active = ref(false)
  20. const fileIpt = ref(null)
  21. defineProps(['accept'])
  22. const handleMouseover = function (event) {
  23. fileIpt.value.focus()
  24. // 粘贴
  25. fileIpt.value.addEventListener('paste', handlePaste)
  26. }
  27. const handleMouseout = function (event) {
  28. fileIpt.value.blur()
  29. fileIpt.value.removeEventListener('paste', handlePaste)
  30. }
  31. onMounted(() => {
  32. // 拖拽
  33. upload.value.addEventListener('drop', handleDrop)
  34. upload.value.addEventListener('dragleave', handleDragleave)
  35. upload.value.addEventListener('dragenter', handleDragenter)
  36. upload.value.addEventListener('dragover', handleDragenter)
  37. upload.value.addEventListener('mouseover', handleMouseover);
  38. upload.value.addEventListener('mouseout', handleMouseout);
  39. })
  40. onUnmounted(() => {
  41. // upload.value.removeEventListener('drop', handleDrop)
  42. // upload.value.removeEventListener('dragleave', handleDragleave)
  43. // upload.value.removeEventListener('dragenter', handleDragenter)
  44. // upload.value.removeEventListener('dragover', handleDragenter)
  45. // upload.value.removeEventListener('mouseover', handleMouseover);
  46. // upload.value.removeEventListener('mouseout', handleMouseout);
  47. })
  48. const emit = defineEmits(["file"])
  49. const handleFileName = (fileList) => {
  50. let files = Array.from(fileList)
  51. let renameReportFile = []
  52. for (let i in files) {
  53. renameReportFile.push(new File([files[i]], new Date().getTime() + files[i].name, { type: files[0].type }))
  54. }
  55. emit("file", renameReportFile[0])
  56. }
  57. const changeFile = (e) => {
  58. e.preventDefault()
  59. handleFileName(e.target.files)
  60. }
  61. const handleDragleave = (e) => {
  62. active.value = false
  63. e.preventDefault()
  64. }
  65. const handleDragenter = (e) => {
  66. active.value = true
  67. e.preventDefault()
  68. }
  69. const handleDrop = (e) => {
  70. e.preventDefault()
  71. active.value = false
  72. handleFileName(e.dataTransfer.files)
  73. }
  74. const handlePaste = (e) => {
  75. e.preventDefault()
  76. handleFileName(e.clipboardData.files)
  77. }
  78. </script>
  79. <style lang="scss" scoped>
  80. @mixin borderColor($color: #2260FF) {
  81. border: 1px dashed $color;
  82. }
  83. .drag {
  84. position: relative;
  85. height: 160px;
  86. @include borderColor(#DEDEDE);
  87. border-radius: 4px;
  88. display: flex;
  89. align-items: center;
  90. flex-direction: column;
  91. justify-content: center;
  92. &:active {
  93. @include borderColor
  94. }
  95. &:hover {
  96. @include borderColor
  97. }
  98. &-active {
  99. @include borderColor
  100. }
  101. &-title {
  102. font-size: 14px;
  103. }
  104. &-subtile {
  105. width: 450px;
  106. font-size: 12px;
  107. color: #999999;
  108. margin-top: 0;
  109. text-align: center;
  110. }
  111. }
  112. .file-ipt {
  113. position: absolute;
  114. top: 0;
  115. left: 0;
  116. width: 100%;
  117. height: 100%;
  118. opacity: 0;
  119. cursor: pointer;
  120. }
  121. .filePaste-ipt {
  122. position: fixed;
  123. right: -100vw;
  124. opacity: 0;
  125. }
  126. </style>