likes
comments
collection
share

💥【Chatterbox(话匣子)】如何实现拖拽、粘贴文件上传?

作者站长头像
站长
· 阅读数 9

背景

获取图片文件

const images = ref([])
const reader = () => {
  images.value = []
  for (let i = 0; i < files.value.length; i++) {
    const file = files.value[i];
    const reader = new FileReader()
    reader.onload = (e) => {  
      images.value.push(e.target.result)
    }
    reader.readAsDataURL(file);  
  }
}

复制图片 粘贴上传

我们先来实现一个简单的-粘贴上传。既然是粘贴,那我们就要监听到粘贴的事件。那我们就可以通过监听paste事件,来获取到粘贴的内容。

el.addEventListener("paste", (event) => {});

事件处理器可以通过调用事件 clipboardData 属性的下的items来访问剪贴板内容。(MDN:可以通过调用事件 clipboardData 属性的 getData() 方法来访问剪贴板内容。)

const pasteHandler = (e) => {
  console.log('🚲 触发粘贴事件:', e);
  files.value = []
  const items = (e.clipboardData || e.originalEvent.clipboardData).items
  for (const index in items) {
    const item = items[index]
    if (item.kind === 'file') {
      files.value.push(item.getAsFile())
    }
  }
  reader()
}

至此粘贴文件上传的功能就已经实现了。

演示

💥【Chatterbox(话匣子)】如何实现拖拽、粘贴文件上传?

拖拽图片上传

接下来实现文件拖拽到目标区域获取对应的文件。既然是拖拽,就要先了解关于拖拽的相关API。这边只介绍我用到的相关API,其它的可以到MDN上自行阅读。👉drag

监听事件

  • dragenter:在可拖动的元素或者被选择的文本进入一个有效的放置目标时触发。
  • dragover:在可拖动的元素或者被选择的文本被拖进一个有效的放置目标时(每几百毫秒)触发。
  • drop:在元素或文本选择被放置到有效的放置目标上时触发。为确保 drop 事件始终按预期触发,应当在处理 dragover 事件的代码部分始终包含 preventDefault() 调用。
  • dragleave:在拖动的元素或选中的文本离开一个有效的放置目标时被触发。

event.preventDefault()

这个方法用于阻止事件的默认行为。‌比如我们正常拖动一个图片文件到浏览器中,它会在一个新的标签页中打开这个图片。我们在实现该上传功能的时候是不希望他打开这个图片,就需要调用该方法来阻止它的默认行为。

event.stopPropagation()

这个方法用于阻止事件冒泡。‌当某个元素被触发某个事件(‌如点击事件)‌时,‌这个事件会从最深的节点(‌或目标节点)‌开始,‌然后逐级向上传播到最少特定节点。‌调用该方法可以阻止这种冒泡行为,‌使得父元素或其他祖先元素无法接收到这个事件。‌

阻止默认行为

经过实验发现只要在拖拽的dragoverdrop两个事件中全都调用event.preventDefault()就可以阻止浏览器在新的页签中打开图片。

const dragHandle = () => {
  const events = ['dragover', 'drop']
  events.forEach(event => {
    refUpload.value.addEventListener(event, e => {
      e.preventDefault()
    })
  })
}

获取拖拽的文件

在拖拽过程中,我们需要在用户在特定区域放下鼠标的时候获取到对应的文件,我们可以drop事件中监听到用户放置行为,并在event.dataTransfer.files可以获取到对应的文件。

const dropHandler = (e) => {
  files.value = e.dataTransfer.files
  reader()
}
refUpload.value.addEventListener('drop', dropHandler)

到此拖拽上传的基本功能都已经实现完成。

优化

在我们实际开发过程中,必然会加上一些样式来提高用户体验。上文中提到了好几个监听事件,到这里还没有用到,下面我们在上方的基础上在进行优化。比方说,当用户拖拽文件到目标区域的时候给目标区域的加上边框。这就比较简单了,当触发dragenter事件的时候,给目标区域的DOM加上对应样式即可。

const addHighlight = () => {
  refUpload.value.classList.add('highlight')
}
refUpload.value.addEventListener('dragenter', addHighlight)

当拖拽文件的离开目标区域或者在目标区域放下文件的时候,我们也要对应的给目标区域的DOM移除对应的样式。即在dragleavedrop事件触发时移除样式。

const removeHighlight = () => {
  refUpload.value.classList.remove('highlight')
}
refUpload.value.addEventListener('dragleave', removeHighlight)

const dropHandler = (e) => {
  removeHighlight()
  files.value = e.dataTransfer.files
  reader()
}
refUpload.value.addEventListener('drop', dropHandler)

拖拽文件到子元素的问题

这里有小坑,当我们的目标区域内还存在子元素的时候。拖动文件到达子元素的时候会触发dragleave事件,相反会触发dragenter。在我们实际开发中,是不希望进入子元素的时候触发dragleave事件的,那样会移除上边给目标区域添加的样式。那我们该如何做呢?下方贴一下我的实现代码:

 let lastElement = null
  refUpload.value.addEventListener('dragenter', e => {
    lastElement = e.target
    addHighlight()
  })
  refUpload.value.addEventListener('dragleave', e => {
    if (e.target === lastElement) {
      removeHighlight()
    }
  })

我通过记录进入时候的元素,当触发dragleave的时候再移除对应的样式。

演示

💥【Chatterbox(话匣子)】如何实现拖拽、粘贴文件上传?

💥【Chatterbox(话匣子)】如何实现拖拽、粘贴文件上传?

以上就是本次分享的内容,由于完整的代码内容过多就不再此粘贴,附上拖拽、粘贴文件上传源码

🦀🦀感谢看官看到这里,如果觉得文章不错的话,可以给小生的几个开源项目点个Star⭐!

转载自:https://juejin.cn/post/7389935779333324811
评论
请登录