Vue project implements file download progress bar function

Vue project implements file download progress bar function

There are two common ways to download files in daily business:

The first one is to directly access the file address of the server and automatically download the file;

The second method is that the server returns a blob file stream, which is then processed and downloaded.

Generally, small files are suitable for the first download solution, which does not occupy too many server resources. For large files, file streaming is often used for transmission, as shown in the figure:

After the file stream is successfully transferred, the browser can be immediately initiated to download the file stream through the code:

This method also has disadvantages. During the file stream transmission process, the user cannot perceive the transmission status (progress) of the file stream, which may cause some troubles (it is impossible to determine whether the current download operation has taken effect). In this case, we can display the status of the file stream and the transfer progress on the page to improve the interactivity and friendliness of the page.

Next is the specific implementation:

Encapsulation js method:

/**
 * @param {Object} data: {url: file address, download: file name}
 */
export function downLoadAll(data) {
  let downProgress = {};
  let uniSign = new Date().getTime() + ''; // You may click to download multiple files in succession. Here, timestamp is used to distinguish each downloaded file axios.get(
    data.url, 
    { responseType: 'blob', headers: { "Content-Type": "application/json; charset=utf-8" },
    onDownloadProgress (progress) {
      downProgress = Math.round(100 * progress.loaded / progress.total) // loaded in the progress object indicates the amount downloaded, and total indicates the total amount. Calculate the percentage herestore.commit('caseInformation/SET_PROGRESS', {path: uniSign, 'progress': downProgress}) // Combine the file name and download progress of this download into an object and use vuex state management}}).then( (res)=>{ // After the file stream transfer is completed, start file downloadif(data.downLoad){
        jsFileDownload(res.data,data.downLoad+'.'+data.url.replace(/.+\./,"")); // jsFileDownLoad is used to download file streams. Download plugin: npm i js-file-download, import: import jsFileDownLoad from 'js-file-download'
      } else {
        jsFileDownload(res.data, data.url.split('/')[data.url.split('/').length-1]);
      }
  }).catch((e)=>{
    this.$message.error('The file cannot be downloaded')
  })
}

caseInfomation.js in the store:

...

const state = {
  progressList: [], // File download progress list...
}

const mutations = {
  SET_PROGRESS: (state, progressObj)=>{ // Modify the progress list if(state.progressList.length){ // If the progress list exists if(state.progressList.find(item=>item.path == progressObj.path)){ // The path timestamp mentioned above is the only one that exists, so if you find the current progress object in the progress list state.progressList.find(item=>item.path == progressObj.path).progress = progressObj.progress // Change the progress of the current progress object
      }
    }else{
      state.progressList.push(progressObj) // The current progress list is empty, there is no download task, directly add the progress object to the progress array}
  },
  DEL_PROGRESS: (state, props) => {
    state.progressList.splice(state.progressList.findIndex(item=>item.path == props), 1) // Delete the progress object in the progress list},
  ...
}

The page displays the progress pop-up code, downLoadNotice.vue:

<template>

</template>

<script>
  import { mapState } from 'vuex'

  export default {
    name: 'downLoadNotice',
    computed: {
      ...mapState({
      'progressList': state => state.caseInformation.progressList
    })
    },
    data() {
      return {
        notify: {} // Used to maintain the download file progress pop-up box object}
    },
    watch: { //Monitor progress list progressList: {
        handler(n) {
          let data = JSON.parse(JSON.stringify(n))
          data.forEach(item => {
            const domList = [...document.getElementsByClassName(item.path)]
            if (domList.find(i => i.className == item.path)) { // If the page already has a pop-up box for the progress object, update its progress
              domList.find(i => i.className == item.path).innerHTML = item.progress + '%'
            } else {
              if (item.progress === null) { // Fault tolerance processing here, if the backend transfer file stream reports an error, delete the current progress object this.$store.commit('caseInformation/DEL_PROGRESS', item.path)
                return
              }// If there is no pop-up box corresponding to the progress object on the page, create a new pop-up box on the page and add the pop-up box object to notify. The attribute name is the path of the progress object (as mentioned above, the path is unique), and the attribute value is $notify (notification component in element ui) pop-up box object this.notify[item.path] = this.$notify.success({
                // title: 'Info',
                dangerouslyUseHTMLString: true,
                message: `<p style="width: 100px;">Downloading<span class="${item.path}" style="float: right">${item.progress}%</span></p>`, // Display the download percentage, the class name is the path of the progress object (to facilitate updating the progress percentage later)
                showClose: false,
                duration: 0
              })
            }
            console.log(item.progress + '%', '-------------------------->')

            if (item.progress == 100) { // If the download progress reaches 100%, close the pop-up window and delete the pop-up window object maintained in notify this.notify[item.path].close()
              // delete this.notify[item.path] The close() event above is asynchronous. Deleting it directly here will result in an error. Use setTimeout to add the operation to the asynchronous queue setTimeout(() => {
                delete this.notify[item.path]
              }, 1000)
              this.$store.commit('caseInformation/DEL_PROGRESS', item.path) // Delete the progress object in the progressList of the state in caseInformation}
          })
        },
        deep: true
      }
    }
  }
</script>

<style scoped>

</style>

We can encapsulate the above code into the mixins folder and mix it into the page using mixins:

Trigger download operation in the page:

downLoad(item){
   let downData = {
      url: `ipdoc${item.url}`,
      downLoad: item.fileName
   }
   this.$commonUtils.downLoadAll(downData) // download},

The final page effect:

Finally, please note that the above download progress is not the actual downloaded file, but the file stream. After the file stream is downloaded, the real file can be downloaded through the js-file-download plug-in mentioned above!

This is the end of this article about implementing file download progress bar in vue project. For more relevant vue file download progress bar content, please search previous articles on 123WORDPRESS.COM or continue to browse the following related articles. I hope you will support 123WORDPRESS.COM in the future!

You may also be interested in:
  • Vue implements drag progress bar
  • Example of implementing circular progress bar in Vue
  • vue.js+ElementUI realizes the effect of progress bar prompting password strength
  • Progress bar function when vue page is loading (example code)
  • Circular loading progress bar encapsulation (Vue plug-in version and native js version)
  • Vue configures nprogress to implement the progress bar at the top of the page
  • How to use NProgress progress bar in Vue

<<:  Detailed process of configuring Https certificate under Nginx

>>:  MySQL functional index optimization solution

Recommend

Detailed explanation of Mysql transaction processing

1. MySQL transaction concept MySQL transactions a...

Detailed tutorial for installing ElasticSearch:7.8.0 cluster with docker

ElasticSearch cluster supports動態請求的方式and靜態配置文件to ...

Use vertical-align to align input and img

Putting input and img on the same line, the img ta...

Linux series of commonly used operation and maintenance commands (summary)

Table of contents 1. System monitoring 2. File Op...

Win10 install Linux ubuntu-18.04 dual system (installation guide)

I installed a Linux Ubuntu system on my computer....

How to create users and manage permissions in MySQL

1. How to create a user and password 1. Enter the...

MySQL 8.0.12 winx64 decompression version installation graphic tutorial

Recorded the installation of mysql-8.0.12-winx64 ...

Example of using swiper plugin to implement carousel in Vue

Table of contents vue - Use swiper plugin to impl...

Solution to nacos not being able to connect to mysql

reason The mysql version that nacos's pom dep...

Use auto.js to realize the automatic daily check-in function

Use auto.js to automate daily check-in Due to the...

Solution to mysql error code 1064

If the words in the sql statement conflict with t...