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

How to create a MySQL database and support Chinese characters

Let's first look at the MySQL official docume...

CentOS 6-7 yum installation method of PHP (recommended)

1. Check the currently installed PHP packages yum...

JavaScript to achieve drop-down menu effect

Use Javascript to implement a drop-down menu for ...

Explain the difference between iframe and frame in HTML with examples

I don't know if you have used the frameset at...

Summary of various uses of JSON.stringify

Preface Anyone who has used json should know that...

Detailed explanation of the payment function code of the Vue project

1. Alipay method: Alipay method: Click Alipay to ...

mysql 5.7.5 m15 winx64.zip installation tutorial

How to install and configure mysql-5.7.5-m15-winx...

HTML scroll bar textarea attribute setting

1. Overflow content overflow settings (set whether...

CSS3 to achieve dynamic background gradient effect

Learning CSS3 is more about getting familiar with...

Detailed explanation of Vue lazyload picture lazy loading example

Documentation: https://github.com/hilongjw/vue-la...

JavaScript adds event listeners to event delegation in batches. Detailed process

1. What is event delegation? Event delegation: Ut...

MySQL Flush-List and dirty page flushing mechanism

1. Review The Buffer Pool will be initialized aft...