Vue implements upload component

Vue implements upload component

1. Introduction

The effect is as follows

2. Ideas

Two ways to upload files

1. From form

<form 
  method="post" 
  enctype="multipart/from-data"
  action="api/upload"
>
  <input type="file name="file">
  <button type="submit">Submit</button>
</form>

The method attribute of form specifies a "post" request, which sends data to the server through an HTML form and returns the modified result of the server. In this case, the Content-Type is set by setting the correct enctype attribute in the <form> element.

The enctype attribute of form specifies how the form data should be encoded before being sent to the server.

  • application/x-www-form-urlencoded (default): means that all characters are encoded before sending. The data is encoded into key-value pairs separated by "&", and the key and value are separated by "=" ("name=seven&age=19"). Binary data is not supported.
  • multipart/form-data: supports binary data (must be specified when uploading files)

2. JavaScript asynchronous request form

We know that the FormData interface provides a way to construct key/value pairs that represent form data, and can easily send data through the XMLHttpRequest.send() method. This interface and this method are quite simple and direct. If the outbound encoding is set to "multipart/form-data", it will use the same format as the form.

var formdata = new FormData(); // Create a FormData object formdata.append("name","laotie"); // Add new attribute values ​​through the append() method... // For more methods, please click the link below

FormData Interface

3. Life Cycle

The upload component also has its life cycle

beforeUpload --> uploading --> fileUploaded or uploadedError

4. Code Draft

In this example, the upload component is developed using js asynchronous request

<input type="file" name="file" @change.prevent="handleFileChange">
// Create an input of type file to trigger file upload. You can hide the input later and customize the style. // When customizing the style, you can use slot to distinguish the styles of different upload states (loading, success, default)
const handleFileChange = (e:Event)=>{
  const target = e.target as HTMLInputElement
  const files = Array.from(target.files)// Note that what is obtained here is a class array if(files){
    // Get the file const uploadedFile = files[0]
    
    if(!validateFormat) return
    // ...This is just a way of thinking, and the specific verification will not be described here // Do some verification before uploading the file, such as file format, size, etc.
    // If it does not meet the requirements, no more requests will be sent const formData = new FormData()
    formData.append(uploadedFile.name,uploadedFile)
    
    axios.post('/upload',formData,{
      headers:{
         // Note to set the encoding type 'Content-Type': 'multipart/form-data'
      }
    }).then(res=>{
      console.log('Upload successful')
    }).catch(error =>{
      // File upload failed}).finally(()=>{
      // File upload completed, whether successful or failed // Here you can clear input.value
    })
  }
}

5. Specific implementation

// Upload.vue
<template>
  <div class="upload-container">
    <div class="upload-box" @click.prevent="triggerUpload" v-bind="$attrs">
      <slot name="loading" v-if="fileStatus==='loading'">
        <button class="btn btn-primary">Uploading</button>
      </slot>
      <slot name="uploaded" v-else-if="fileStatus==='success'" :uploadedData="fileData">
        <button class="btn btn-primary">Upload successful</button>
      </slot>
      <slot v-else name="default">
        <button class="btn btn-primary">Click to upload</button>
      </slot>
    </div>
    <input type="file" class="file-input d-none" name="file" ref="uploadInput" @change="hanldeInput"/>
  </div>
</template>
<script lang="ts">
import { defineComponent, ref, PropType, watch } from 'vue'
import axios from 'axios'
type UploadStatus = 'ready' | 'loading' | 'success' | 'error'
type FunctionProps = (file:File) => boolean
export default defineComponent({
  name: 'Upload',
  inheritAttrs: false,
  props: {
    // Upload url
    action: {
      type: String,
      required: true
    },
    // Verification before uploading, a function that returns a Boolean value beforeUpload: {
      type: Function as PropType<FunctionProps>
    },
    // Uploaded data, used to determine status or initialize display uploadedData: {
      type: Object
    }
  },
  emits: ['file-uploaded-success', 'file-uploaded-error'],
  setup(props, ctx) {
    const uploadInput = ref<null | HTMLInputElement>(null)
    const fileStatus = ref<UploadStatus>(props.uploadedData ? 'success' : 'ready')
    const fileData = ref(props.uploadedData)
    watch(() => props.uploadedData, (val) => {
      if (val) {
        fileStatus.value = 'success'
        fileData.value = val
      }
    })
    const triggerUpload = () => {
      if (uploadInput.value) {
        uploadInput.value.click()
      }
    }
    const hanldeInput = (e:Event) => {
      const target = e.target as HTMLInputElement
      const files = target.files
      console.log(target)
      if (files) {
        const uploadFile = Array.from(files)
        const validateFormat = props.beforeUpload ? props.beforeUpload(uploadFile[0]) : true
        if (!validateFormat) return
        fileStatus.value = 'loading'
        const formData = new FormData()
        formData.append('file', uploadFile[0])
        axios.post(props.action, formData, {
          headers: {
            'Content-Type': 'multipart/form-data'
          }
        }).then(res => {
          console.log('File uploaded successfully', res)
          fileStatus.value = 'success'
          fileData.value = res.data
          ctx.emit('file-uploaded-success', res.data)
        }).catch(error => {
          console.log('File upload failed', error)
          fileStatus.value = 'error'
          ctx.emit('file-uploaded-error', error)
        }).finally(() => {
          console.log('File upload completed')
          if (uploadInput.value) {
            uploadInput.value.value = ''
          }
        })
      }
    }

    return {
      uploadInput,
      triggerUpload,
      hanldeInput,
      fileStatus,
      fileData
    }
  }
})
</script>

Example of use:

<template>
  <div class="create-post-page">
    <upload
      action="/upload"
      :beforeUpload="beforeUpload"
      :uploadedData="uploadedData"
      @file-uploaded-success="hanldeUploadSuccess"
      class="d-flex align-items-center justify-content-center bg-light text-secondary w-100 my-4"
      >
      <template #uploaded="slotProps">
        <div class="uploaded-area">
          <img :src="slotProps.uploadedData.data.url"/>
          <h3>Click to re-upload</h3>
        </div>
       </template>
       <template #default>
         <h2>Click to upload header image</h2>
       </template>
       <template #loading>
         <div class="d-flex">
          <div class="spinner-border text-secondary" role="status">
            <span class="sr-only"></span>
          </div>
         </div>
       </template>
    </upload>
  </div>
</template>
<script lang="ts">
import { defineComponent, ref, onMounted } from 'vue'
import Upload from '../components/Upload.vue'
import createMessage from '../components/createMessage'

export default defineComponent({
  name: 'CreatePost',
  components: { Upload },
  setup() {
    const uploadedData = ref() //Create a responsive data let imageId = ''
    onMounted(() => {
      ....
      // The logic is omitted here, get the initialization data image
      if (image) {
        uploadedData.value = { data: image }
      }
    })
    // Verify before uploading, return Boolean value const beforeUpload = (file:File) => {
      const res = beforeUploadCheck(file, {
        format: ['image/jpeg', 'image/png'],
        size: 1
      })
      const { error, passed } = res
      if (error === 'format') {
        createMessage('Uploaded images can only be in JPG/PNG format!', 'error')
      }
      if (error === 'size') {
        createMessage('Uploaded image size cannot exceed 1MB', 'error')
      }
      return passed
    }
    // After the upload is successful, you can get the imageId for subsequent processing, such as creating a form. const hanldeUploadSuccess = (res:ResponseProps<ImageProps>) => {
      createMessage(`Upload image ID ${res.data._id}`, 'success')
      if (res.data._id) {
        imageId = res.data._id
      }
    }
    return {
      beforeUpload,
      hanldeUploadSuccess,
      uploadedData
    }
  }
})
</script>
<style>
.create-post-page{
  padding:0 20px 20px;
}
.create-post-page .upload-box{
  height:200px;
  cursor: pointer;
  overflow: hidden;
}
.create-post-page .upload-box img{
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.uploaded-area{
  position: relative;
}
.uploaded-area:hover h3{
  display: block;
}
.uploaded-area h3{
  display: none;
  position: absolute;
  color: #999;
  text-align: center;
  width: 100%;
  top:50%
}
</style>

The above is the details of Vue's upload component implementation. For more information about the Vue upload component, please pay attention to other related articles on 123WORDPRESS.COM!

You may also be interested in:
  • vue-cropper component realizes image cutting and uploading
  • vue-cropper plug-in realizes the encapsulation of image capture and upload component
  • Implementation of Vue image cropping and uploading component
  • Vue3.0 with .net core to implement file upload component
  • Vue example of using native components to upload pictures
  • Vue + Node.js + MongoDB image upload component to implement image preview and deletion functions
  • Detailed explanation of the use of Vue image upload component
  • Use elementUI component in vue to manually upload pictures
  • Vue development package upload file component and usage examples
  • Detailed explanation of the use of Vue image upload local preview component
  • Use of vue-cli3.0+element-ui upload component el-upload

<<:  MySQL 8.0.13 installation and configuration method graphic tutorial under Windows 64 bit

>>:  CentOS 7.6 installation of MySQL 5.7 GA version tutorial diagram

Recommend

A QQ chat room based on vue.js

Table of contents Introduction The following is a...

How to build php-nginx-alpine image from scratch in Docker

Although I have run some projects in Docker envir...

Summary of learning HTML tags and basic elements

1. Elements and tags in HTML <br />An eleme...

Front-end JavaScript Promise

Table of contents 1. What is Promise 2. Basic usa...

Windows Server 2008 R2 Multi-User Remote Desktop Connection Licensing

At work, we often need remote servers and often e...

Implementation of Nginx configuration https

Table of contents 1: Prepare https certificate 2:...

Detailed explanation of MySQL basic operations (Part 2)

Preface This article contains 1. Several major co...

Detailed explanation of mysql basic operation statement commands

1. Connect to MySQL Format: mysql -h host address...

Docker build PHP environment tutorial detailed explanation

Docker installation Use the official installation...

WeChat applet implements simple chat room

This article shares the specific code of the WeCh...

Problems and experiences encountered in web development

<br />The following are the problems I encou...

Summary of several common logs in MySQL

Preface: In the MySQL system, there are many diff...

Win7 installation MySQL 5.6 tutorial diagram

Table of contents 1. Download 2. Installation 3. ...