vue项目实现文件下载中心:下载、取消下载、列表展示
vue项目实现文件下载中心:下载、取消下载、列表展示实现下载进度条封装JS方法使用store存储文件下载进度列表创建一个列表组件在页面中使用效果展示实现下载进度条平时业务中下载文件方式常见的有俩种:第一种,直接访问服务器的文件地址,自动下载文件;第二种 ,服务器返回blob文件流,再对文件流进行处理和下载。第一种自行百度第二种方式有弊端,在文件流传输过程中,用户无法感知文件流的传输状态(进度),会
·
实现下载进度条
平时业务中下载文件方式常见的有俩种:
第一种,直接访问服务器的文件地址,自动下载文件;
第二种 ,服务器返回blob文件流,再对文件流进行处理和下载。
第一种自行百度
第二种方式有弊端,在文件流传输过程中,用户无法感知文件流的传输状态(进度),会造成一些困扰(无法确定当前下载操作是否已经生效)。针对这种情况,我们可以在页面显示文件流的状态和传输进度,提高页面交互性和友好性。
封装JS方法
/**
* @param {Object} data: {url: 文件地址, download: 文件名称}
*/
import axios from "axios";
import jsFileDownLoad from 'js-file-download'
import store from "@/store/index"
import {ElMessage} from "element-plus";
export function downLoadAll(data) {
let downProgress = {};
let uniSign = Date.now(); //可能会连续点击下载多个文件,这里用时间戳来区分每一次下载的文件
//通过传递一个 executor 函数到 CancelToken 的构造函数来创建 cancel token:
const CancelToken = axios.CancelToken;
let cancel;
axios.get(
data.url,
{
responseType: 'blob', headers: {"Content-Type": "application/json; charset=utf-8"},
//取消axios的函数
cancelToken: new CancelToken(function executor(c) {
// executor 函数接收一个 cancel 函数作为参数
cancel = c;
}),
onDownloadProgress(progress) {
downProgress = Math.round(100 * progress.loaded / progress.total) // progress对象中的loaded表示已经下载的数量,total表示总数量,这里计算出百分比
store.commit('SET_PROGRESS', {
path: uniSign,
name: data.downLoad,
progress: downProgress,
status: downProgress == 100 ? 'success' : 'downloading',
cancel: cancel
}) // 将此次下载的文件名和下载进度组成对象再用vuex状态管理
}
}).then((res) => { // 文件流传输完成后,开启文件下载
if (data.downLoad) {
jsFileDownLoad(res.data, data.downLoad); // jsFileDownLoad是用来下载文件流的,下载插件:npm i js-file-download,import引入:import jsFileDownLoad from 'js-file-download'
//文件下载成功提示一下。此处我是用的Element-plus提示框
if (downProgress == 100) {
ElMessage.success("Download Complete:" + data.downLoad)
}
} else {
jsFileDownLoad(res.data, data.url.split('/')[data.url.split('/').length - 1]);
}
}).catch((e) => {
if (JSON.stringify(e) == "{}") {
ElMessage.error("Download Cancelled:" + data.downLoad)
} else {
ElMessage.error("Download Failed:" + data.downLoad)
}
store.commit('SET_PROGRESS', {
path: uniSign,
name: data.downLoad,
progress: downProgress,
status: 'error',
cancel: cancel
})
})
}
使用store存储文件下载进度列表
/store/download.js
const downloadStore={
state: {
progressList:[]
},
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
state.progressList.find(item=>item.path == progressObj.path).status = progressObj.status // 改变当前进度对象的status
}else{
state.progressList.push(progressObj) // 当前进度列表为空,没有下载任务,直接将该进度对象添加到进度数组内
}
}else{
state.progressList.push(progressObj) // 当前进度列表为空,没有下载任务,直接将该进度对象添加到进度数组内
}
},
DEL_PROGRESS: (state, props) => {
state.progressList.splice(state.progressList.findIndex(item=>item.path == props), 1) // 删除进度列表中的进度对象
},
},
actions:{
},
getters:{
progressList:state=>state.progressList,
}
}
export default downloadStore;
创建一个列表组件
/components/DownloadList/index.vue
<template>
<el-table :data="progressList">
<el-table-column prop="name" label="Name"></el-table-column>
<el-table-column prop="status" label="Status">
<template #default="scope">
<!-- 显示文件状态 -->
<el-tag v-if="scope.row.status=='downloading'">Downloading</el-tag>
<el-tag v-if="scope.row.status=='success'" type="success">Success</el-tag>
<el-tag v-if="scope.row.status=='error'" type="danger">Download failed</el-tag>
</template>
</el-table-column>
<el-table-column label="Progress">
<!-- 根据状态判断使用不同的进度条 -->
<template #default="scope">
<el-progress :percentage="scope.row.progress" v-if="scope.row.status=='downloading'"/>
<el-progress :percentage="scope.row.progress" v-if="scope.row.status=='success'" status="success"/>
<el-progress :percentage="scope.row.progress" v-if="scope.row.status=='error'" status="exception"/>
</template>
</el-table-column>
<el-table-column width="80px">
<template #default="scope">
<!--点击按钮取消下载 -->
<el-icon v-if="scope.row.status=='downloading'" style="cursor: pointer" color="#F56C6C"
@click="handleDownloadClose(scope.row)">
<close-bold/>
</el-icon>
</template>
</el-table-column>
</el-table>
</template>
<script>
export default {
name: "index",
props: {
progressList: {
type: Object,
default: []
}
},
methods: {
handleDownloadClose(row) {
if (row.status == 'downloading') {
row.cancel()
}
}
}
}
</script>
<style scoped>
</style>
在页面中使用
假设现在有一个文件列表fileList
<template>
//点击按钮显示文件下载中心
<el-button icon="download" type="primary" @click="handleDownloadTable">Download</el-button>
//文件列表
<el-table :data="progressList">
<el-table-column prop="name" label="Name"></el-table-column>
<el-table-column width="80">
<template #default="scope">
<div @click="handleDownload(scope.row)">Download</div>
</template>
</el-table-column>
</el-table>
<el-drawer v-model="drawerDownload" title="Download">
<DownloadList :progressList="progressList"></DownloadList>
</el-drawer>
</template>
<script>
import DownloadList from "@/components/DownloadList/index.vue"
export default {
name: "index",
components:{DownloadList},
data(){
return{
drawerDownload:false,//下载中心以抽屉的形式打开
progressList:[//文件列表
{
name:1,
file_url:'www.baidu.com'
}
]
}
}
methods:{
handleDownload(row){
ElMessage.success("Downloading. It can be viewed at the download center")
let downData = {
url: row.file_url,
downLoad: row.name
}
downLoadAll(downData) // 下载
},
handleDownloadTable(){
this.drawerDownload=true
},
}
}
</script>
<style scoped>
</style>
效果展示
本文参考链接:https://www.cnblogs.com/coder–wang/p/15320511.html
axios文档地址:http://www.axios-js.com/zh-cn/docs/#%E5%8F%96%E6%B6%88
更多推荐
已为社区贡献8条内容
所有评论(0)