electron-updater实现electron全量更新和增量更新——渲染进程UI部分

devtools/2024/9/22 15:45:12/

同学们可以私信我加入学习群!


正文开始

  • 前言
  • 更新功能所有文章汇总
  • 一、两个同心球效果实现
  • 二、球内进度条、logo、粒子元素实现
    • 2.1 球内包含几个元素:
    • 2.2 随机粒子生成方法generateRandomPoint
    • 2.3 创建多个粒子的方法createParticle
  • 三、gsap创建路径动画,实现粒子动画
  • 总结


前言

更新功能的实现分为三篇文章来讲解:
1.主进程更新
2.开发调试技巧
3.渲染进程部分。

我在开发过程中,是先开发的主进程主要功能,再完善渲染进程部分的显示。因为当没有前端时,可以写几个简单的标签显示结果,保证主要功能基本完成,再完善前端交互。
效果图如下:
在这里插入图片描述
上面有几个简单的交互:

  • 打开软件时,页面向主进程通信,查询是否更新
  • 发现需要更新,弹出一个更新交互页面,页面显示更新信息和更新操作
  • 更新时,点击关闭按钮,会进入后台更新模式,登录进去后,点击左上角的更新标志,会弹出更新页面。

大的需求就是这样三个,至于细节后文再展开叙述,比如跳过版本如何实现,如何保障登录页和登录后,更新的进度是保持一致的……

更新功能所有文章汇总

  1. electron-updater实现electron全量更新和增量更新——主进程部分
  2. electron-updater实现electron全量更新和增量更新——注意事项/技巧汇总
  3. electron-updater实现electron全量更新和增量更新——渲染进程UI部分
  4. electron-updater实现electron全量更新和增量更新——渲染进程交互部分

一、两个同心球效果实现

在讲解前,我们先整体了解一下前端的文件结构:
在这里插入图片描述

  • updateprogress.vue是唯一的vue文件
  • updateBall.js:和中间的球相关的逻辑
  • updateHandle.js:操作按钮相关的逻辑
  • store/update.js:更新模块的全局变量

静态页面部分没什么好说的,就是一个遮罩加两个球,还有一些按钮,我的审美并不好,大家可以自行设计。球的立体效果就是靠阴影效果,代码如下:

<div:style="{ width: ballRadius * 2 + 'px', height: ballRadius * 2 + 'px' }"class="ball"></div><style scope>
.ball {border-radius: 50%;//background: linear-gradient(135deg, #fff, #ddd);background-color: #fff;box-shadow: inset 0 0 0 2px rgba(0, 0, 0, .1),0 0 10px 2px rgba(0, 0, 0, .1);display: flex;align-items: center;justify-content: center;position: relative;overflow: hidden;flex-direction: column;
}.ball::before {content: "";width: 80%;height: 80%;border-radius: 50%;//background: linear-gradient(315deg, #ddd, #fff);background-color: #fff;box-shadow: inset 0 0 0 2px rgba(0, 0, 0, .1),0 0 10px 2px rgba(0, 0, 0, .1);position: absolute;
}
</style>

类ball是外层的大球,设置的半径ballRadius 为100,伪类:before是小球,大球小球靠阴影效果,塑造立体感。

二、球内进度条、logo、粒子元素实现

2.1 球内包含几个元素:

  • logo
  • 不规则的粒子
  • 进度条

外层的ball采用的flex布局,布局方向是纵向,所以logo通过图片标签直接引入,设置好宽高即可,下面依次写进度条、粒子等元素:

 <div :style="{width:ballRadius*2+'px',height:ballRadius*2+'px'}" class="ball"><img alt="Logo" class="logo" src="/public/img/log-opacity.png"><div style="display: flex;flex-direction: column;width: 60%"><Progress :percent="update_info.percent || 0" :stroke-width="5" style="flex-grow: 1;margin-right: 4px"><div style="width: 100%;display: flex;flex-direction: row;justify-content: center;align-content: center"><span>{{ update_info.percent || 0 }}%</span><span style="color: #1a1a1a;margin-left: 8px">{{ update_info.speed || '0kb' }}</span></div></Progress></div><div class="particles"><!--        循环渲染粒子--><div v-for="(particleItem,index) in particlesList":key="index":ref="el => setItemRef(index, el)":style="{left: particleItem.left+'px',top:particleItem.top+'px',backgroundColor:particleItem.color}"class="particle"></div></div></div>

2.2 随机粒子生成方法generateRandomPoint

重点讲解一下上面的粒子渲染。

首先,粒子的容器是和最大的球重合的,所以采用absolute定位,css代码如下:

.particles {position: absolute;width: 100%;height: 100%;
}

粒子渲染最重要的是随机在圆环位置生成粒子的逻辑,这部分的算法核心其实就是初中数学知识:

  1. 外球半径(outRadius)-内球半径(radius)=圆环半径
  2. 圆环半径*随机数+内球半径(radius)=落在圆环内的随机半径
  3. 落在圆环内的随机半径*角度的cos和sin值,就分别是随机半径终点的坐标

转化为代码就是:

//生成radius外,outRadius内圆环上的坐标const randomRadius = radius + Math.random() * (outRadius - radius)const outX = randomRadius * Math.cos(angle)const outY = randomRadius * Math.sin(angle)

上面的代码就会生成angle角度方向,不同半径的坐标,如果angle角度也是随机的,那么就会生成圆环内随机散布的粒子

const angle = Math.random() * (2 * Math.PI)const randomRadius = radius + Math.random() * (outRadius - radius)const outX = randomRadius * Math.cos(angle)const outY = randomRadius * Math.sin(angle)

然后根据这个算法,我又增加了两种场景,一种是随机粒子是在内球半径上,得到粒子的坐标,思路是一样的,就不再赘述:

        //生成半径radius上的坐标const innerX = Math.random() * radius * Math.cos(angle)const innerY = Math.random() * radius * Math.sin(angle)

另一种是随机粒子是在内球半径内,也就是粒子随机散布在小球内:

       //生成半径radius内的坐标const innerX = Math.random() * radius * Math.cos(angle)const innerY = Math.random() * radius * Math.sin(angle)

最终这个方法就是:

 function generateRandomPoint(radius, outRadius) {//根据半径生成随机坐标,radiusArr:半径上的坐标,outRadiusArr:半径外的坐标,innerRadiusArr:半径内的坐标//outRadiusArr只有存在外环半径outRadius时才会生成// 生成一个0到2π之间的随机角度const angle = Math.random() * (2 * Math.PI)// 极坐标到笛卡尔坐标的转换,生成半径radius上的坐标const x = radius * Math.cos(angle)const y = radius * Math.sin(angle)//生成半径radius内的坐标const innerX = Math.random() * radius * Math.cos(angle)const innerY = Math.random() * radius * Math.sin(angle)//生成radius外,outRadius内的坐标// debuggerconst randomRadius = radius + Math.random() * (outRadius - radius)const outX = randomRadius * Math.cos(angle)const outY = randomRadius * Math.sin(angle)return {radiusArr: [x, y],innerRadiusArr: [innerX, innerY],outRadiusArr: [outX, outY]}}

本文的设计是将粒子散布在圆环内,所以只需要返回值的outRadiusArr参数即可。

2.3 创建多个粒子的方法createParticle

通过上面的generateRandomPoint方法,我们可以得到粒子的一个随机坐标。只要我们循环调用该方法,那就会循环得到粒子的不同坐标,代码如下:

    function createParticle(num) {// debugger
//  根据num生成随机粒子for (let i = 0; i < num; i++) {const {outRadiusArr: [outX, outY]} = generateRandomPoint(70, ballRadius.value)const particle = {color: getRandomRGBColor(),left: 100 + outX,top: 100 + outY,}particlesList.value.push(particle)}}

其中的getRandomRGBColor方法是获取随机颜色的方法:

    function getRandomRGBColor() {// 限制绿色和蓝色分量在100到255之间,红色分量在0到100之间const r = Math.floor(Math.random() * 101) // 0 to 100const g = Math.floor(Math.random() * 156) + 100 // 100 to 255const b = Math.floor(Math.random() * 156) + 100 // 100 to 255return `rgb(${r}, ${g}, ${b})`}

最终使用vue的v-for将粒子循环渲染到页面。

三、gsap创建路径动画,实现粒子动画

使用gsap插件,可以很方便地实现元素围绕某个路径运动。不仅限于圆弧,还可以是曲线、折线、不规则图形,gsap是flash基于js上的实现,功能十分强大,有兴趣的同学可以查看往期博文,这里不重点阐述概念。

创建动画的方法如下:

    function createAnimation(movementRange = 3) {// 使用GSAP创建动画particlesList.value.forEach((particle, index) => {// 使用GSAP创建动画gsap.to(particleRefs.value[index], {motionPath: {path: '#svg',align: '#svg',alignOrigin: [Math.random() * 10 - 5, Math.random() * 10 - 5]},repeat: -1, // 无限重复duration: 3 * Math.random() + 2, // 随机持续时间ease: 'linear', // 线性运动delay: Math.random() * 2 // 随机延迟})})}

这里有几个小技巧:

  1. 仔细的同学可以发现,在vue中,粒子的ref变量是通过setItemRef方法实现的
	//vue中的代码<div v-for="(particleItem,index) in particlesList":key="index":ref="el => setItemRef(index, el)":style="{left: particleItem.left+'px',top:particleItem.top+'px',backgroundColor:particleItem.color}"class="particle"></div>//对应的js代码     function setItemRef(index, el) {if (el) {// 如果元素存在,则将其存储在对象中particleRefs.value[index] = el} else {// 如果元素不存在(可能是被销毁了),则从对象中删除delete particleRefs.value[index]}}

这个方法最终会得到一个保存粒子ref对象的数组particleRefs。

  1. gsap动画需要指定动画元素, gsap.to的第一个参数particleRefs.value[index]就是循环得到的动画元素,也就是每一个粒子。
  2. gsap的基础配置十分简单,这里主要是讲解motionPath参数。这是路径插件的参数:
   motionPath: {path: '#svg',align: '#svg',alignOrigin: [Math.random() * 10 - 5, Math.random() * 10 - 5]},

前面两个参数好理解,就是粒子绕着路径运动,总得先定义路径,svg就是路径的id。alignOrigin是粒子偏移路径的距离,使用随机数,可以让粒子运动效果有杂乱随机的感觉。
4. svg是路径path的id,不是svg标签的id,这个要注意,对应的svg代码如下:

  <!-- SVG 圆形元素 --><svg style="position: absolute" height="95%" viewBox="-160 -160 320 320" width="95%"xmlns="http://www.w3.org/2000/svg"><path id="svg"d="M 0 160A 160 160 0 0 1 0 -160A 160 160 0 0 1 0 160 Z"fill="transparent" stroke="none"/></svg>

构建svg的时候,还要注意原点、是否闭合、起止点等信息,也就是d元素中的数据。如果d属性的路径设置不合理,可能会造成path路径与外部的圆不重合的问题。当然这些一般没人去手输,通过Adobe AI软件、在线svg绘制网站、ai助手等,都可以得到符合要求的svg路径。

对svg不熟悉的同学,要关注viewBox属性,这是svg可以跟随父级容器按照比例增大缩小的关键。

  1. 启动动画:当用户点击立即更新时,需要做三件事:1)创建200个粒子;2)启动动画;3)检查更新。代码如下:
    function startUpdate() {createParticle(200)setTimeout(() => {createAnimation()myApi.handlePcToUpdate()}, 100)}

总结

本文主要是讲解了更新模块的页面样式实现,下一篇文章讲解页面上的交互逻辑实现。

大家如果需要联系博主,或者获取博主各系列文章对应的资源,可以通过中二少年学编程的个人主页来获取。

有任何前端项目、demo、教程需求,都可以联系博主,博主会视精力更新,免费的羊毛,不薅白不薅!~


http://www.ppmy.cn/devtools/87940.html

相关文章

CDH清理磁盘空间完全攻略和完整实现自动化脚本(大数据清除日志)

在CDH集群中,自动清除日志的意义非常重大。尤其是在内网环境下,运维人员无法随时登录服务器进行操作,或者是因为放长假等原因不能每天进行运维工作。这时,如果日志不自动清理,就会面临日志空间满了的问题,这可能造成CDH各组件无法正常工作,离线数仓计算完全停止。 考虑…

使用WebSocket实现log日志流的实时展示-从轮询到通知

场景介绍 最近开发一个系统&#xff0c;其中一个模块需要展示实时的执行过程&#xff0c;过程日志可能比较多。以前的方案都是前端定时轮询&#xff0c;比如每秒查一次后端接口&#xff0c;将拉取回来的日志重新展示。轮询方案简单容易实现&#xff0c;但是比较消耗资源&#…

掌控板(为Python编程学习而生)文章目录+入门教程 简介

前言 文章目录 掌控入门系列教程目录 【Mind】掌控板入门教程01 “秀”出我创意 【Mind】掌控板入门教程02 趣味相框 【Mind】掌控板入门教程03 节日的祝福【Mind】掌控板入门教程04 迷你动画片【Mind】掌控板入门教程05 心情灯【Mind】掌控板入门教程06 多彩呼吸灯【Mind】掌…

Spring Boot 动态数据源

目录 前言 前置环境 pom yml Entity Dao 枚举类 数据源 AOP Controller 启动类 演示 前言 大多数系统中&#xff0c;都需要数据库来持久化数据&#xff0c;在大多数情况下&#xff0c;一个系统只需要配置一个数据源便能够完成所有业务的查询&#xff0c;保存操作。…

[ACTF2020 新生赛]BackupFile1

打开题目 利用disearch扫描&#xff0c;发现源文件index.php.bak 下载下来 打开文件 代码审计&#xff0c;翻译一下 翻译代码为&#xff1a; <?php include_once "flag.php"; //这一行使用 include_once 函数来包含&#xff08;或插入&#xff09;另一个 PHP …

第三方库jsoncpp

文章目录 0.jsoncpp库是做什么的&#xff1f;1.安装库2.有哪几个类&#xff0c;如何使用Json::Value类Json::Writer类-StreamWriterJson::Reader类-CharReader三者关系 3.使用样例将数据先存入Value类&#xff0c;再通过StreamWriter类转为Json格式的字符串获取到Json格式字符串…

大厂的风控引擎架构设计

1 架构师能力思维模型 全局思维抽象思维 2 新需求的思考路径 需求是否合理&#xff0c;是否能解决问题&#xff1f; 能划分多少个子系统&#xff1f; 每个子系统能划分多少个模块&#xff1f;这个系统需要可靠性吗&#xff0c;需要扩展能力吗&#xff1f;成本需要控制吗&a…

【教程】Python语言的地球科学常见数据——海温数据-NOAA OISST 的处理

NOAA 1/4每日最佳内插海面温度&#xff08;OISST&#xff09;是一个长期的气候数据记录&#xff0c;它将来自 不同平台&#xff08;卫星、船舶、浮标和 Argo 浮标&#xff09;的观测数据纳入一个定期的全球网格。该 数据集经过插值处理&#xff0c;以填补网格上的空白&#x…