vue下载

常规下载

  • request.js
mport { Loading } from 'element-ui'

// 请求实例
const instance = axios.create({
  baseURL: process.env.VUE_APP_BASE_API,
  timeout: 5000
})
/**
 * 下载
 * @param url
 * @param data
 */
export function download(url, data, fileName) {
  return new Promise((resolve, reject) => {
    // 打开
    const loading = Loading.service({
      text: '正在下载数据...',
      background: 'rgba(0, 0, 0, 0.7)'
    })

    instance.request({
      url: url,
      method: 'post',
      data: data,
      timeout: 1200000,
      responseType: 'blob'
    }).then(res => {
      loading.close()

      // 文件下载
      const blob = new Blob([res.data], {
        type: 'application/vnd.ms-excel'
      })

      // 获得文件名称
      let link = document.createElement('a')
      link.href = URL.createObjectURL(blob)
      link.setAttribute('download', fileName)
      link.click()
      link = null
      Message.success('导出成功!')
    }).catch(err => {
      loading.close()
      reject(err)
    })
  })
}
  • api.js
import {download } from '@/utils/request'
export function exportExcel(data) {
return download('url', data, '导出的数据.xlsx')
}
  • .vue
download(this.data)

带进度条下载

  • 公共方法
import store from '@/store'
downFileProgress  =(url,parameter,callback,totalSize,uniSign) =>{
  return axios({
    url: url,
    params: parameter,
    method:'get' ,
    responseType: 'blob',
    onDownloadProgress (progress) {
      let total =progress.total|| progress.srcElement.getResponseHeader('Content-Length')
      // console.log(progress); 
      downProgress = (100 * progress.loaded / total).toFixed(2)
      // progress对象中的loaded表示已经下载的数量,total表示总数量,这里计算出百分比
      store.commit('downLoadProgress/SET_PROGRESS', { path: uniSign, 'progress': downProgress }) // 将此次下载的文件名和下载进度组成对象再用vuex状态管理
    }
  })
}
  • 新建src\store\modules\downLoadProgress.js文件
const state = {
    // 文件下载进度
    progressList: [],
    progressError: '',
    isDown:false
}
const mutations = {
    SET_PROGRESS: (state, progressObj) => {
        // 修改进度列表
        if (state.progressList.length) {
            // 如果进度列表存在
            if (state.progressList.find(item => item.path == progressObj.path)) {
                // 前面说的path时间戳是唯一存在的,所以如果在进度列表中找到当前的进度对象
                state.progressList.find(item => item.path == progressObj.path).progress = progressObj.progress
                // 改变当前进度对象的progress
            }
        } else {
            // 当前进度列表为空,没有下载任务,直接将该进度对象添加到进度数组内
            state.progressList.push(progressObj)
        }
    },
    DEL_PROGRESS: (state, props) => {
        state.progressList.splice(state.progressList.findIndex(item => item.path == props), 1) // 删除进度列表中的进度对象
    },
    CHANGE_SETTING: (state, { key, value }) => {
        // eslint-disable-next-line no-prototype-builtins
        if (state.hasOwnProperty(key)) {
            state[key] = value
        }
    },
    updateDown(state, val) {
      state.isDown = val
    }
}

const actions = {
    changeSetting({ commit }, data) {
        commit('CHANGE_SETTING', data)
    }
}

export default {
    namespaced: true,
    state,
    mutations,
    actions
}

  • src\store\index.js
import Vue from 'vue'
import Vuex from 'vuex'
import downLoadProgress from './modules/downLoadProgress'
import getters from './getters'

Vue.use(Vuex)

const store = new Vuex.Store({
  modules: {
    downLoadProgress
  },
  state: {
  },
  mutations: {
  },
  getters
})

export default store
  • 新建src\components\downLoadNotice\index.vue文件
<template>
</template>

<script>
  import { mapState } from 'vuex'

  export default {
    name: 'downLoadNotice',
    computed: {
      ...mapState({
      'progressList': state => state.downLoadProgress.progressList
    })
    },
    data() {
      return {
        notify: {} // 用来维护下载文件进度弹框对象
      }
    },
    watch: { // 监听进度列表
      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)) { // 如果页面已经有该进度对象的弹框,则更新它的进度progress
              if(item.progress)domList.find(i => i.className == item.path).innerHTML = item.progress + '%'
              if (item.progress === null) { // 此处容错处理,如果后端传输文件流报错,删除当前进度对象
                this.$store.commit('downLoadProgress/DEL_PROGRESS', item.path)
                this.$notify.error({
                  title: '错误',
                  message: '文件下载失败!'
                });
              }
            } else {
              // 如果页面中没有该进度对象所对应的弹框,页面新建弹框,并在notify中加入该弹框对象,属性名为该进度对象的path(上文可知path是唯一的),属性值为$notify(element ui中的通知组件)弹框对象
              this.notify[item.path] = this.$notify.success({
                // title: 'info',
                dangerouslyUseHTMLString: true,
                customClass: 'progress-notify',
                message: `<p style="width: 130px;">正在下载<span class="${item.path}" style="float: right">${item.progress}%</span></p>`, 
                // 显示下载百分比,类名为进度对象的path(便于后面更新进度百分比)
                showClose: false,
                duration: 0
              })
            }
            this.$store.commit('updateDown', true)
            console.log(item.progress + '%', '-------------------------->')
            if (item.progress == 100) { // 如果下载进度到了100%,关闭该弹框,并删除notify中维护的弹框对象
                
              this.notify[item.path].close()
              // delete this.notify[item.path] 上面的close()事件是异步的,这里直接删除会报错,利用setTimeout,将该操作加入异步队列
              setTimeout(() => {
                delete this.notify[item.path]
              }, 1000)
              this.$store.commit('updateDown', false)
              this.$store.commit('downLoadProgress/DEL_PROGRESS', item.path)// 删除caseInformation中state的progressList中的进度对象
            }
          })
        },
        deep: true
      }
    }
  }
</script>

<style lang="scss" scoped>

</style>

  • 在App.vue文件中引入
<down-load-notice></down-load-notice>

import downLoadNotice from "@/components/downLoadNotice/index"
components: { downLoadNotice },

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值