vue项目实现文件下载中心:下载、取消下载、列表展示

37 篇文章 3 订阅

实现下载进度条

平时业务中下载文件方式常见的有俩种:

第一种,直接访问服务器的文件地址,自动下载文件;

第二种 ,服务器返回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

  • 6
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
### 回答1: Vue和ElementUI是一对非常强大的前端开发工具,可以帮助我们快速实现增删改查功能。具体实现步骤如下: 1. 安装Vue和ElementUI 首先需要安装Vue和ElementUI,可以使用npm或yarn进行安装。 2. 创建Vue组件 创建一个Vue组件,包含增删改查的功能。可以使用ElementUI提供的组件,如表格、表单、对话框等。 3. 实现数据绑定 使用Vue的数据绑定功能,将组件中的数据和页面中的元素进行绑定。可以使用v-model指令实现双向数据绑定。 4. 实现增删改查功能 使用Vue的方法和事件处理功能,实现增删改查的功能。可以使用axios或fetch等工具进行数据的请求和响应。 5. 完成样式设计 使用ElementUI提供的样式和自定义样式,完成页面的样式设计。 以上就是使用Vue和ElementUI实现增删改查功能的基本步骤。需要注意的是,具体实现过程可能会因为项目需求的不同而有所差异。 ### 回答2: Vue ElementUI 是一套基于 Vue.js 的开源 UI 组件库,提供了丰富的组件和样式库,使开发人员可以更方便、快速地创建美观,符合规范的项目界面。本文将以 Vue ElementUI 为基础,介绍如何实现增删改查功能。 一、安装 Vue ElementUI 首先,需要安装 Vue.js 和 ElementUI。 在命令行中执行以下命令安装: ``` npm install vue npm install element-ui ``` 二、创建 Vue ElementUI 项目 在命令行中执行以下命令来创建一个新的 Vue ElementUI 项目。 ``` vue create vue-elementui-demo ``` 三、在Vue文件中引入ElementUI组件库 修改App.vue文件,引入ElementUI组件库。 ``` <template> <div id="app"> <el-header>Header</el-header> <el-main>Main Content</el-main> <el-footer>Footer</el-footer> </div> </template> <script> import ElementUI from 'element-ui'; import 'element-ui/lib/theme-chalk/index.css'; export default { name: 'app', components: { 'el-header': ElementUI.Header, 'el-main': ElementUI.Main, 'el-footer': ElementUI.Footer } }; </script> ``` 四、创建增删改查页面 首先,在src目录下创建一个名为views的文件夹,用于存放页面组件。在views文件夹中新建一个名为user.vue的组件文件用于实现增删改查页面。 创建一个表格用于显示用户列表,并添加一个操作列,用于添加、编辑和删除操作。代码如下: ``` <template> <div class="user"> <el-button @click="handleCreate">新建</el-button> <el-table :data="tableData" style="width: 100%"> <el-table-column prop="name" label="姓名"></el-table-column> <el-table-column prop="gender" label="性别"></el-table-column> <el-table-column prop="age" label="年龄"></el-table-column> <el-table-column label="操作"> <template slot-scope="scope"> <el-button @click="handleEdit(scope.row)">编辑</el-button> <el-button @click="handleDelete(scope.row)">删除</el-button> </template> </el-table-column> </el-table> </div> </template> <script> export default { data() { return { tableData: [ {name: "张三", gender: "男", age: "18"}, {name: "李四", gender: "女", age: "20"}, {name: "王五", gender: "男", age: "22"} ] } }, methods: { handleCreate() { // TODO: 弹出新建对话框 }, handleEdit(row) { // TODO: 弹出编辑对话框 }, handleDelete(row) { // TODO: 弹出删除确认对话框,确认后从tableData中删除该行数据 } } } </script> ``` 五、实现新建、编辑、删除对话框 为了实现新建、编辑、删除操作,需要实现对应的对话框组件。创建一个名为user-dialog.vue的组件文件用于实现这些对话框。 代码如下: ``` <template> <el-dialog :title="title" :visible.sync="dialogVisible"> <el-form :model="form" label-position="left" label-width="80px"> <el-form-item label="姓名"> <el-input v-model="form.name"></el-input> </el-form-item> <el-form-item label="性别"> <el-radio-group v-model="form.gender"> <el-radio label="男">男</el-radio> <el-radio label="女">女</el-radio> </el-radio-group> </el-form-item> <el-form-item label="年龄"> <el-input v-model="form.age"></el-input> </el-form-item> </el-form> <div slot="footer" class="dialog-footer"> <el-button @click.native="dialogVisible = false">取消</el-button> <el-button type="primary" @click.native="handleSave">保存</el-button> </div> </el-dialog> </template> <script> export default { props: { title: { type: String, required: true }, visible: { type: Boolean, required: true }, form: { type: Object, required: true } }, computed: { dialogVisible: { get() { return this.visible; }, set(val) { this.$emit('update:visible', val); } } }, methods: { handleSave() { this.$emit('save'); } } } </script> ``` 在user.vue中引入user-dialog.vue组件,并为每个操作添加对应的处理函数来弹出对应的对话框。 代码如下: ``` <template> <div class="user"> <el-button @click="handleCreate">新建</el-button> <el-table :data="tableData" style="width: 100%"> <!-- 省略的列 --> </el-table> <user-dialog title="新建用户" :visible.sync="createDialogVisible" :form="createForm" @save="handleCreateSave"/> <user-dialog title="编辑用户" :visible.sync="editDialogVisible" :form="editForm" @save="handleEditSave"/> <el-dialog title="删除确认" :visible.sync="deleteDialogVisible"> <p>确定要删除“{{deleteForm.name}}”吗?</p> <div slot="footer" class="dialog-footer"> <el-button @click.native="deleteDialogVisible = false">取消</el-button> <el-button type="danger" @click.native="handleDelete">删除</el-button> </div> </el-dialog> </div> </template> <script> import UserDialog from '@/views/user-dialog.vue'; export default { components: { UserDialog }, data() { return { tableData: [ {id: 1, name: "张三", gender: "男", age: "18"}, {id: 2, name: "李四", gender: "女", age: "20"}, {id: 3, name: "王五", gender: "男", age: "22"} ], createDialogVisible: false, createForm: { name: "", gender: "男", age: "" }, editDialogVisible: false, editForm: { id: 0, name: "", gender: "", age: "" }, deleteDialogVisible: false, deleteForm: { id: 0, name: "" } } }, methods: { handleCreate() { this.createForm.name = ""; this.createForm.gender = "男"; this.createForm.age = ""; this.createDialogVisible = true; }, handleCreateSave() { const id = Math.max(0, ...this.tableData.map(item => item.id)) + 1; const data = {... this.createForm, id}; this.tableData.push(data); this.createDialogVisible = false; }, handleEdit(row) { this.editForm.id = row.id; this.editForm.name = row.name; this.editForm.gender = row.gender; this.editForm.age = row.age; this.editDialogVisible = true; }, handleEditSave() { const index = this.tableData.findIndex(item => item.id === this.editForm.id); if (index >= 0) { this.tableData.splice(index, 1, this.editForm); } this.editDialogVisible = false; }, handleDelete(row) { const index = this.tableData.findIndex(item => item.id === row.id); if (index >= 0) { this.tableData.splice(index, 1); } this.deleteDialogVisible = false; }, handleDeleteSave() { this.handleDelete(this.deleteForm); } } } </script> ``` 以上就是如何使用 Vue ElementUI 实现增删改查功能的介绍,希望对你有所帮助。 ### 回答3: Vuejs是目前最流行的前端框架之一,随着其火爆的发展,越来越多的公司和开发者喜欢使用Vuejs开发项目,其中Vuejs与element-ui的组合是目前最常用的一种方式,element-ui提供了一整套完整的UI组件库,可以轻松地实现页面开发。在实现增删改查功能时,Vuejs与element-ui非常适合,可以极大地提高我们的开发效率,让我们快速实现各种功能。 首先,我们需要安装Vue-cli 3.x版本,使用Vue-cli创建一个Vue项目,安装element-ui库。我们还需要安装axios库,它可以用来与后端API通信。 接下来,我们需要创建一个列表页,将数据展示在页面上,同时还需要添加按钮以执行相应的操作。这个列表页可以通过element-ui的table组件来实现,同时使用axios库与后端api通信,获取数据并将其渲染到页面上。 在实现增加数据功能时,我们可以通过一个Dialog弹窗来实现,通过展示表单进行新增数据操作。此时我们就需要用到element-ui的Dialog组件,将表单组件放在Dialog里面,同时使用axios与后端进行通信。 修改数据同样也可以使用弹窗进行实现,只需要在弹窗的表单里填入需要修改的数据,通过axios向后端发送更新请求即可。 最后,删除数据可以通过一些操作按钮来处理,例如:删除按钮,勾选数据后点击删除按钮即可。在处理完删除数据请求之后,使用axios与后端进行通信。 总之,使用Vuejs与element-ui一起开发增删改查功能是一种很高效的方式,这个组合可以大大提高我们前端开发的效率,减少开发周期。同时各种组件也可以通过element-ui的样式来保证我们UI的一致性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值