electron展示下载进度条

我们使用electron下载文件时,会发现不像浏览器一样会有地方展示下载进度,这导致下载一些大文件时不知道下载进度到哪里了

下面我们通过electron提供的will-download监听和element-plus中的ElNotificationElProgress组件实现这一功能
在这里插入图片描述

实现逻辑

  1. 触发下载文件这一操作
  2. 监听下载开始、下载进度、下载结束
  3. 根据监听内容操作vnode展示加载进度

1、触发下载文件这一操作

使用electron中ipcMain模块接受页面中发送来的指令

// main.js 部分代码 通过这个打开****.vue界面 
var win = new BrowserWindow();
//  download.js 部分代码
const { ipcMain, dialog } = require('electron')
let filePath = '';
    // 监听渲染进程发出的download事件
const webContents = win.webContents;
 ipcMain.on('download', (evt, args) => {
     const fileArr = args.split("/");
     let ext = path.extname(args)

     let filters = [{ name: '全部文件', extensions: ['*'] }]
     if (ext && ext !== '.') {
       filters.unshift({
         name: '',
         extensions: [ext.match(/[a-zA-Z]+$/)[0]]
       })
     }
     dialog.showSaveDialog(win, {
         filters,
         defaultPath:args
     }).then( res => {
         if(res.filePath){
             filePath = res.filePath
             webContents.downloadURL(args) // 注意这里必须是下载文件可访问路径。而不是存储路径
         }
     })
 })
 // vue页面中的逻辑 ***.vue
 import { ipcRenderer } from "electron"
 // 触发
 var url = '下载地址.***'
 ipcRenderer.send('download', url)

执行完上面的代码会弹窗另存为下载,会发现下载没有显示进度的地方

2、监听下载开始、下载进度、下载结束

监听webContents中的will-download事件会返回下载相关的一些信息,这里把下载过程中的一些状态和用到的一些参数发送给webContents中打开的页面

// download.js 部分代码
 webContents.session.on('will-download', (event, item, webContents) => {
        item.setSavePath(filePath) // 这里是存储路径或者存储文件名称
        var filName = path.basename(filePath)
        win.webContents.send('win-will-download',{type:'start',params:{filName}})
        item.on('updated', (event, state) => {
            if (state === 'interrupted') {
                console.log('Download is interrupted but can be resumed')
            } else if (state === 'progressing') {
                if (item.isPaused()) {
                    console.log('Download is paused')
                } else {
                    win.webContents.send('win-will-download',{type:"progress",params:{
                        totalBytes:item.getTotalBytes(),
                        receivedBytes:item.getReceivedBytes()
                    }})
                }
            }

        })
        item.once('done', (event, state) => {
            if (state === 'completed') {
                win.webContents.send('win-will-download',{type:"completed"})
                console.log('Download successfully')
            } else {
                console.log(`Download failed: ${state}`)
            }
        })
    })
 // ***.vue
 //download是展示下载进度的组件,下面会有相应的代码 这里通过ref创建响应数据 vue2的话可以通过 Vue.observable API进行创建
import download from "@/components/download/index.vue"
import { ElNotification } from 'element-plus'
import { h, ref } from 'vue'
var totalBytes = ref(0)
var receivedBytes = ref(0)

 mounted(){
	 ipcRenderer.removeAllListeners('win-will-download')
	 ipcRenderer.on('win-will-download', this.winDownLoadFun)
 },
 methods:{
 	
 	winDownLoadFun(event, data) {
      if (data.type == 'start') {
        this.notice && this.notice.close && this.notice.close()
        var progress = h(download, {
          totalBytes: totalBytes,
          receivedBytes: receivedBytes,
          filName: data.params.filName,
          onClose: () => {
            totalBytes.value = 0
            receivedBytes.value = 0
            this.notice && this.notice.close && this.notice.close()
          }
        })
        this.notice = ElNotification({
          title: '下载进度',
          position: 'bottom-right',
          duration: 0,
          showClose: false,
          message: progress,
          onClose: () => {
            this.notice = null
          }
        })
      }
      else if (data.type == 'progress') {
        totalBytes.value = data.params.totalBytes
        receivedBytes.value = data.params.receivedBytes
      } else if (data.type == 'completed') {
        receivedBytes.value = totalBytes.value
      }
    },
 } 

3、根据监听内容操作vnode展示加载进度

下面是download/index.vue完整文件

<template>
    <div style="width: 100%;">
        <div>
            <div @click="$emit('close')" v-if="percentage == 100" style="position: absolute;top: 15px;right: 15px;cursor: pointer;">关闭</div>
            <div class="task-item">
                <img class="img" src="@/assets/image/zip-1.png"></img>
                <div class="name">
                    <div>{{filName}}</div>
                    <div class="progress1">{{limitFormat(receivedBytes.value)}}/{{limitFormat(totalBytes.value)}}</div>
                </div>
            </div>

            <div>
                <el-progress :show-text="false" :percentage="percentage" />
            </div>
        </div>
    </div>
</template>

<script>
import { ElMessage, ElProgress } from 'element-plus'
import { ref } from 'vue'
export default {
    name: 'download',
    props: {
        filName:{
            type:String,
            default:""
        },
        totalBytes: {
            default() {
                return ref(0)
            }
        },
        receivedBytes: {
            default() {
                return ref(0)
            }
        }
    },
    computed:{
        percentage(){
           return parseFloat((((this.receivedBytes.value / this.totalBytes.value) ||0 )* 100).toFixed(2)) 
        }
    },
    watch:{
        percentage(){
            if(this.percentage == 100 && this.totalBytes.value != 0){
                ElMessage({
                    message:"下载完成!",
                    type:"success"
                })
            }
        },
    },
    methods: {
        limitFormat(limit) {
            var size = "";
            if (limit < 0.1 * 1024) { //小于0.1KB,则转化成B
                size = limit.toFixed(2) + "B"
            } else if (limit < 0.1 * 1024 * 1024) { //小于0.1MB,则转化成KB
                size = (limit / 1024).toFixed(2) + "KB"
            } else if (limit < 0.1 * 1024 * 1024 * 1024) { //小于0.1GB,则转化成MB
                size = (limit / (1024 * 1024)).toFixed(2) + "MB"
            } else { //其他转化成GB
                size = (limit / (1024 * 1024 * 1024)).toFixed(2) + "GB"
            }

            var sizeStr = size + ""; //转成字符串
            var index = sizeStr.indexOf("."); //获取小数点处的索引
            var dou = sizeStr.substr(index + 1, 2) //获取小数点后两位的值
            if (dou == "00") { //判断后两位是否为00,如果是则删除00
                return sizeStr.substring(0, index) + sizeStr.substr(index + 3, 2)
            }
            return size;
        }
    },

}
</script>

<style scoped>
.task-item {
    width: 280px;
    display: flex;
    align-items: center;
    margin-bottom: 6px;
}

.progress1 {
    font-size: 12px;
    margin-top: -4px;
    color: #999;
}

.task-item i {}

.img {
    width: 32px;
    height: 32px;
    display: block;
    margin-right: 14px;

}
</style>

download.js完整代码

const { ipcMain, dialog, shell } = require('electron')
const path = require('path')
const fs = require('fs');
const { type } = require('os');
exports.initDownload = function (win) {
    let filePath = '';
    // 监听渲染进程发出的download事件
    const webContents = win.webContents;
    ipcMain.on('download', (evt, args) => {
        const fileArr = args.split("/");
        let ext = path.extname(args)

        let filters = [{ name: '全部文件', extensions: ['*'] }]
        if (ext && ext !== '.') {
          filters.unshift({
            name: '',
            extensions: [ext.match(/[a-zA-Z]+$/)[0]]
          })
        }
        dialog.showSaveDialog(win, {
            filters,
            defaultPath:args
        }).then( res => {
            if(res.filePath){
                filePath = res.filePath
                webContents.downloadURL(args) // 注意这里必须是下载文件可访问路径。而不是存储路径
            }
        })
    })
    webContents.session.on('will-download', (event, item, webContents) => {
        item.setSavePath(filePath) // 这里是存储路径或者存储文件名称
        var filName = path.basename(filePath)
        win.webContents.send('win-will-download',{type:'start',params:{filName}})
        item.on('updated', (event, state) => {
            if (state === 'interrupted') {
                console.log('Download is interrupted but can be resumed')
            } else if (state === 'progressing') {
                if (item.isPaused()) {
                    console.log('Download is paused')
                } else {
                    win.webContents.send('win-will-download',{type:"progress",params:{
                        totalBytes:item.getTotalBytes(),
                        receivedBytes:item.getReceivedBytes()
                    }})
                }
            }

        })
        item.once('done', (event, state) => {
            if (state === 'completed') {
                win.webContents.send('win-will-download',{type:"completed"})
                console.log('Download successfully')
            } else {
                console.log(`Download failed: ${state}`)
            }
        })
    })
}

main.js中使用代码
这里的main.js是electron的主进程文件,不是vue相关的问题

const { BrowserWindow } = require("electron");
const {initDownload} = require('@/utils/download.js')
var win = null;
async function createWindow() {
	win = new BrowserWindow({
	// 创建相关的参数
	});
	// 为创建的win窗口绑定下载事件
	initDownload(win)
}
createWindow()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/904855.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【算法】(Python)回溯算法

回溯算法&#xff1a; 回溯算法是一种算法思想。采用“深度优先搜索&#xff08;dfs&#xff0c;depth first search&#xff09;”。采用“尝试”和“回溯”的策略。尝试搜索所有可能的解决方案&#xff0c;遇到不满足条件的撤销选择、回退到回溯点&#xff08;满足回溯条件的…

音视频入门基础:FLV专题(18)——Audio Tag简介

一、引言 根据《video_file_format_spec_v10_1.pdf》第75页&#xff0c;如果某个Tag的Tag header中的TagType值为8&#xff0c;表示该Tag为Audio Tag&#xff1a; 这时StreamID之后紧接着的就是AudioTagHeader&#xff0c;也就是说这时Tag header之后的就是AudioTagHeader&…

探索Python终端美化的终极利器:Rich库

文章目录 &#x1f680; 探索Python终端美化的终极利器&#xff1a;Rich库第一部分&#xff1a;背景介绍第二部分&#xff1a;Rich库是什么&#xff1f;第三部分&#xff1a;如何安装Rich库&#xff1f;第四部分&#xff1a;Rich库的简单函数使用方法第五部分&#xff1a;结合场…

【Java笔记】1-JDK/JRE/JVM是个啥?

JDK、JRE、JVM可以说是入门必须了解的三个词汇 先说全称 JDK&#xff1a;Java Development Kit&#xff0c;Java开发工具包 JRE&#xff1a;Java Runtime Environment&#xff0c;Java运行环境 JVM&#xff1a;Java Virtual Machine&#xff0c;Java虚拟机 再说关系 JVM⊆J…

视觉目标检测标注xml格式文件解析可视化 - python 实现

视觉目标检测任务&#xff0c;通常用 labelimage标注&#xff0c;对应的标注文件为xml。 该示例来源于开源项目&#xff1a;https://gitcode.com/DataBall/DataBall-detections-100s/overview 读取 xml 标注文件&#xff0c;并进行可视化示例如下&#xff1a; #-*-coding:ut…

金和OA-C6 ApproveRemindSetExec.aspx XXE漏洞复现(CNVD-2024-40568)

0x01 产品描述&#xff1a; 金和C6协同管理平台是以"精确管理思想"为灵魂&#xff0c;围绕“企业协同四层次理论”模型&#xff0c;并紧紧抓住现代企业管理的六个核心要素&#xff1a;文化 Culture、 沟通Communication 、 协作Collaboration 、创新 Creation、 控制…

ETL集成工具丨如何运用ETLCloud单步调试断点功能

在现代数据处理领域&#xff0c;ETLCloud 的单步调试断点功能正成为数据管理的重要工具。ETLCloud 是一个强大的云端数据处理平台&#xff0c;它提供了灵活的单步调试功能&#xff0c;使得用户能够逐步跟踪和分析数据处理流程。本文将探讨如何运用 ETLCloud 的单步调试断点功能…

GB/T 28046.2-2019 道路车辆 电气及电子设备的环境条件和试验 第2部分:电气负荷(3)

写在前面 本系列文章主要讲解道路车辆电气及电子设备的环境条件和试验GB/T 28046标准的相关知识&#xff0c;希望能帮助更多的同学认识和了解GB/T 28046标准。 若有相关问题&#xff0c;欢迎评论沟通&#xff0c;共同进步。(*^▽^*) 第2部分&#xff1a;电气负荷 4.9 抛负载…

开源陪玩系统平台源码-支持游戏线上陪玩家政线下预约等多场景应用支持H5+小程序+APP

陪玩平台的流行可以归因于多个因素&#xff0c;包括现代生活的快节奏和压力、电竞行业的带动、孤独经济的兴起&#xff0c;以及技术的进步等。这些因素共同推动了陪玩平台的发展&#xff0c;使其成为人们寻求社交互动和休闲娱乐的重要途径。 现代生活的快节奏和压力 现代生活…

1:基本电路专题:R(电阻)的介绍

说实话这个其实我不想写的&#xff0c;因为这个是初中的知识&#xff0c;并没有很难&#xff0c;但是为了保持整齐性&#xff0c;我还是写了一下关于这个的知识点。是电子学中三大基本无源元件之一。&#xff08;R&#xff08;电阻&#xff09;,L&#xff08;电感&#xff09;,…

解决注册Kaggle出现的“Captcha must be filled out”问题

首先&#xff0c;出现这个问题后&#xff0c;就搜索了一下别的博主的方法。 使用header editor 插件 首先&#xff0c;下载扩建&#xff1a; 然后进行重定向&#xff1a; 管理之后&#xff0c;输入下面的地址&#xff0c;然后下载-保存&#xff1a; 但是&#xff0c;这条显然…

大模型面试题持续更新_Moe(2024-10-30)

扫一扫下方&#xff0c;获取更多面试真题的集合 Moe和集成学习方法有什么异同&#xff1f; MoE和集成学习的思想异曲同工&#xff0c;都是集成了多个模型的方法&#xff0c;Moe主要是将预测任务分为多个子任务&#xff0c;然后通过路由网络的形式决定对于当前的数据该使用哪个…

Vue-$el属性

原博客地址&#xff1a;深入 Vue.js 的心脏&#xff1a;全面剖析 $el 属性_vue $el-CSDN博客 目录 1 $el是什么 1.1 $el本质 1.2 访问$el时机 1.3 $el与模板的关系 2 $el使用场景 2.1 集成第三方库 2.2 操作DOM元素样式 2.3 处理焦点和事件 2.4 实现自定义指令 3 $e…

小满OKKICRM与钉钉数据集成方案解析

小满-宜搭产品同步&#xff1a;小满OKKICRM数据集成到钉钉的技术实现 在企业信息化建设中&#xff0c;系统间的数据集成是提升业务效率和数据一致性的关键环节。本文将聚焦于“小满-宜搭产品同步”方案&#xff0c;详细探讨如何将小满OKKICRM的数据高效、可靠地集成到钉钉平台…

【prefect】Prefect二:python任务调度工具 Prefect 基础使用教程 | work pool | Deployment | flow

一、Work Pool 1、什么是 Work Pool 白话解释&#xff1a;集中管理部署脚本的开关 Work pools allow you to switch between different types of infrastructure and to create a template for deployments. Data platform teams find work pools especially useful for mana…

蓝海创意云入选中国夏衍电影学会工业与科技影视专业委员会成员单位

党的二十届三中全会指出&#xff0c;科技自立自强是中国式现代化的有力保障。科技兴则民族兴&#xff0c;科技强则国家强。为深入的贯彻落实这一重要部署&#xff0c;推动工业与科技领域的融合发展充分发挥电影艺术在传播科技创新精神、展现工业发展成就方面的独特作用&#xf…

基于SpringBoot的“CSGO赛事管理系统”的设计与实现(源码+数据库+文档+PPT)

基于SpringBoot的“CSGO赛事管理系统”的设计与实现&#xff08;源码数据库文档PPT) 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SpringBoot 工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 系统首页界面图 赛事信息界面图 赛事通知界面…

WPF+MVVM案例实战(十三)- 封装一个自定义消息弹窗控件(上)

文章目录 1、案例效果2、功能实现1、创建文件2、资源文件获取3、枚举实现3、弹窗实现1、界面样式实现2、功能代码实现4、总结1、案例效果 2、功能实现 1、创建文件 打开 Wpf_Examples 项目,我们在用户控件类库中创建一个窗体文件 SMessageBox.xaml,同时创建枚举文件夹 Enum…

室内障碍物射线追踪算法matlab模拟仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 (完整程序运行后无水印) 增加发射点 加入室内墙壁&#xff1a; 同时增加发射点和室内墙壁&#xff1a; 2.算法运行软件版本 matlab2022a 3.部分…

荒野大镖客:救赎 PC版整合包

游戏名称&#xff1a;荒野大镖客&#xff1a;救赎 英文名称&#xff1a;Red Dead Redemption 游戏类型&#xff1a;动作冒险类(ACT)游戏 游戏制作&#xff1a;Rockstar Games/Double Eleven 游戏发行&#xff1a;Rockstar Games 游戏平台&#xff1a;PC 发售时间&#xff1a;20…