Vue3 + Nodejs practical, file upload project-implementing drag and drop upload

Table of contents

 1. Analysis of drag and drop upload

The input file is dragged by default

 Make other boxes become drag objects

2. Process file uploads

Data processing

Function to upload files

Taking into account click events

Render processed files

Test effect

3. Summary


 Blog homepage:専心_frontend,javascript,mysql-CSDN blog

 Column series: vue3+nodejs practice--file upload

 Front-end code repository:jiangjunjie666/my-upload: vue3+nodejs upload file project for learning (github.com)

 Backend code repository:jiangjunjie666/my-upload-server: nodejs backend for uploading files (github.com)

 Welcome to pay attention

In the previous article, we implemented batch upload of files and displayed real-time upload progress,Vue3 + Nodejs actual combat, file upload project--implementing file batch upload (display Real-time upload progress)_専心的blog-CSDN Blog

This article mainly discusses the idea and implementation of drag-and-drop uploading.​ 

 1. Analysis of drag and drop upload

The input file is dragged by default

In fact, according to my current understanding (of course I am not very mature and I am still learning hard, if I am wrong, please correct me), uploading files is actually mainly about two points. The first one is the interaction of the page (drag and drop) style, displayed upload progress bar, etc.), the second one is network communication to send the file to the backend through post request, so we have already written the interface for uploading files in the last issue, this time it is mainly to complete the interaction of the front-end page logic.

Drag-and-drop uploading is actually supported in the native input selection box.

 

So we can fill the entire upload box with input and set its opacity to 0 to achieve a hidden effect, and support both drag and click.

However, this is generally not done in actual development. Different styles are generally implemented based on the design draft. The input boxes are always hidden. In the hidden state, files cannot be dragged into their scope.​ 

 Make the box a drag object

The above input supports drag and drop effects because it exists as a drag and drop object in native HTML5, but the compatibility may not be particularly good. At this time, we can also turn other boxes into drag and drop objects. object.

 Below is the box where we store the entire drag-and-drop upload area, which we set as the drag-and-drop object.

<div class="container" @dragenter.prevent="handleDragEnter" @dragover.prevent="handleDragOver" @drop.prevent="handleDrop"></div>

We have bound some events to him

  • dragover event: When the drag object hovers over an element (that is, when the drag object moves on the element), the dragover event will continue to fire.

  • dragenter event: When the drag object enters an element for the first time, the dragenter event will be triggered.

  • dragleave event: When the drag object leaves an element, the dragleave event will be triggered.

  • drop event: When the dragging object releases the mouse button on the element, the drop event will be triggered.

We only need to block enter and over here.

// 处理拖拽进入
const handleDragEnter = (e) => {
  e.preventDefault()
  console.log('Drag entered')
}
// 处理拖拽过程中
const handleDragOver = (e) => {
  e.preventDefault() // 阻止默认行为
  // 处理拖拽过程中的操作
  console.log('Drag over')
}
// 处理拖拽事件
const handleDrop = (e) => {
  e.preventDefault()
  const files = e.dataTransfer.files
  console.log('上传的文件:', files)
}

Now you can drag and drop files to upload. Just drag and drop to the specified area. To get the data, use e.dataTransfer.flies.

2. Process file uploads

Data processing

We can define an array to place the files to be uploaded and an array to place the files that have been processed.

//存放已经上传的文件的数组
let fileListOver = ref([])
//存放要上传的文件的数组
let fileList = ref([])

Data is pushed into the array after the drag event

// 处理拖拽事件
const handleDrop = (e) => {
  e.preventDefault()
  const files = e.dataTransfer.files
  console.log('上传的文件:', files)
  //将要上传的文件放入数组中
  fileList.value.push(...files)
  uploadFile()
}

Function to upload files

This interface for uploading files uses the interface written in the previous video. If you haven’t seen it, you can read the previous oneVue3 + Nodejs actual combat, file upload project-implementation file Batch upload (display real-time upload progress)_専心的blog-CSDN Blog

Next, you can upload files and process the uploaded data. Because we can select multiple files, we need to recursively judge the uploaded files. Don’t forget to import the constructor of axios before doing this

 

//上传文件的函数
const uploadFile = async () => {
  //先要计算出要上传的文件的索引
  const index = fileListOver.value.length
  if (fileList.value.length == fileListOver.value.length) {
    //所有的数据都已经上传完毕,退出递归
    return
  }
  //存放文件数据
  let formData = new FormData()
  formData.append('file', fileList.value[index])
  console.log(formData)
  let res = await http.post('/api/fileUpload', formData)
  if (res.code !== 200) {
    fileListOver.value.push({
      name: fileList.value[index].name,
      size: fileList.value[index].size > 1024 * 1024 ? (fileList.value[index].size / 1024 / 1024).toFixed(2) + 'mb' : (fileList.value[index].size / 1024).toFixed(2) + 'kb',
      status: 'error'
    })
    ElMessage({
      type: 'error',
      message: res.msg
    })
  } else {
    //将上传好的数据插入至fileListOver中
    fileListOver.value.push({
      name: fileList.value[index].name,
      size: fileList.value[index].size > 1024 * 1024 ? (fileList.value[index].size / 1024 / 1024).toFixed(2) + 'mb' : (fileList.value[index].size / 1024).toFixed(2) + 'kb',
      status: 'scuuess'
    })
    ElMessage({
      type: 'success',
      message: '上传成功'
    })
  }
  //开个定时器
  let timer = setTimeout(() => {
    uploadFile() //递归
    clearTimeout(timer)
  }, 1000)
}

Taking into account click events

Because we definitely support file selection by dragging and dropping files, we will do some compatibility here. It is actually very simple. After reading the previous issues, it is easy to do this.

let fileInputRef = ref(null)

// input的监听事件
const handlerChange = (e) => {
  //将点击上传的文件添加到fileList中
  fileList.value.push(...e.target.files)
  // 调用函数
  uploadFile()
}

// 点击上传按钮
const handlerUpload = () => {
  fileInputRef.value.click()
}

Render processed files

 <!-- 这里显示已经拖拽上传了的文件 -->
  <el-table :data="fileListOver" style="width: 80%">
    <el-table-column prop="name" label="文件名" width="450" />
    <el-table-column prop="size" label="文件大小" width="200" />
    <!-- 控制显示 -->
    <el-table-column label="文件状态" width="300">
      <template #default="scope1">
        <span v-if="scope1.row.status == 'scuuess'" style="color: #67c23a">上传成功</span>
        <span v-if="scope1.row.status == 'error'" style="color: red">上传失败</span>
      </template>
    </el-table-column>
  </el-table>

Test effect

selected

uploading

 

upload completed 

 

All code

<template>
  <div class="container" :class="{ draging: dragStyle == true }" @dragenter.prevent="handleDragEnter" @dragover.prevent="handleDragOver" @drop.prevent="handleDrop">
    <el-icon size="200" class="icon" @click="handlerUpload"><UploadFilled /></el-icon>
    <input type="file" multiple @change="handlerChange" ref="fileInputRef" class="ipt" style="display: none" />
  </div>
  <!-- 这里显示已经拖拽上传了的文件 -->
  <el-table :data="fileListOver" style="width: 80%">
    <el-table-column prop="name" label="文件名" width="450" />
    <el-table-column prop="size" label="文件大小" width="200" />
    <!-- 控制显示 -->
    <el-table-column label="文件状态" width="300">
      <template #default="scope1">
        <span v-if="scope1.row.status == 'scuuess'" style="color: #67c23a">上传成功</span>
        <span v-if="scope1.row.status == 'error'" style="color: red">上传失败</span>
      </template>
    </el-table-column>
  </el-table>
</template>

<script setup>
import { ref } from 'vue'
import { http } from '@/api/http.js'
import { ElMessage } from 'element-plus'
let fileInputRef = ref(null)
//存放已经上传的文件的数组
let fileListOver = ref([])
//存放要上传的文件的数组
let fileList = ref([])
//拖拽样式
let dragStyle = ref(false)
// input的监听事件
const handlerChange = (e) => {
  //将点击上传的文件添加到fileList中
  fileList.value.push(...e.target.files)
  // 调用函数
  uploadFile()
}

// 点击上传按钮
const handlerUpload = () => {
  fileInputRef.value.click()
}

// 处理拖拽进入
const handleDragEnter = (e) => {
  e.preventDefault()
  //添加拖拽样式
  dragStyle.value = true
}
// 处理拖拽过程中
const handleDragOver = (e) => {
  e.preventDefault() // 阻止默认行为
}
// 处理拖拽事件
const handleDrop = (e) => {
  e.preventDefault()
  const files = e.dataTransfer.files
  console.log('上传的文件:', files)
  //将要上传的文件放入数组中
  fileList.value.push(...files)
  dragStyle.value = false
  uploadFile()
}
//上传文件的函数
const uploadFile = async () => {
  //先要计算出要上传的文件的索引
  const index = fileListOver.value.length
  if (fileList.value.length == fileListOver.value.length) {
    //所有的数据都已经上传完毕,退出递归
    return
  }
  //存放文件数据
  let formData = new FormData()
  formData.append('file', fileList.value[index])
  console.log(formData)
  let res = await http.post('/api/fileUpload', formData)
  if (res.code !== 200) {
    fileListOver.value.push({
      name: fileList.value[index].name,
      size: fileList.value[index].size > 1024 * 1024 ? (fileList.value[index].size / 1024 / 1024).toFixed(2) + 'mb' : (fileList.value[index].size / 1024).toFixed(2) + 'kb',
      status: 'error'
    })
    ElMessage({
      type: 'error',
      message: res.msg
    })
  } else {
    //将上传好的数据插入至fileListOver中
    fileListOver.value.push({
      name: fileList.value[index].name,
      size: fileList.value[index].size > 1024 * 1024 ? (fileList.value[index].size / 1024 / 1024).toFixed(2) + 'mb' : (fileList.value[index].size / 1024).toFixed(2) + 'kb',
      status: 'scuuess'
    })
    ElMessage({
      type: 'success',
      message: '上传成功'
    })
  }
  //开个定时器
  let timer = setTimeout(() => {
    uploadFile() //递归
    clearTimeout(timer)
  }, 1000)
}
</script>

<style lang="scss" scoped>
.container {
  width: 800px;
  height: 300px;
  margin: 20px 100px;
  border: 2px dashed #ccc;
  display: flex;
  justify-content: center;
  align-items: center;
  .ipt {
    width: 100%;
    height: 100%;
    opacity: 0;
    display: none;
  }
  .icon {
    color: #ccc;
  }
  .icon:hover {
    cursor: pointer;
  }
  //拖拽样式
  .draging {
    background-color: #ecf5ff;
    border: 2px dashed #eaebec;
    .icon {
      color: pink;
    }
  }
}
</style>

3. Summary

 The essence of drag-and-drop uploading is the interaction between the user and the page. In fact, there are not many difficulties involved. As long as you know how to set a div or a container as a drag-and-drop object, the problem of drag-and-drop uploading will be easily solved. If you don’t understand or Better solutions can be communicated via private message or comments.

The next article is about implementing multi-part upload of large files, please pay attention.

Guess you like

Origin blog.csdn.net/m0_64642443/article/details/133828584