记录--进度条真的是匀速的,不信你看

news/2024/9/19 8:09:45/文章来源:https://www.cnblogs.com/smileZAZ/p/18316639

🧑‍💻 写在开头

点赞 + 收藏 === 学会🤣🤣🤣

引言

众所周知,进度条是程序员大大模拟的程序运行进度,一般会在某些数值卡住不动,引起99%悬案。但是背后的原理你真的清楚吗,其实进度条真的是匀速运动的!

先来看看效果

接下来开始实现

创建一个矩形,然后折叠起来,完成!

创建一个容器,用于宽度限制

折叠形状实际大小肯定是大于需求大小的,在这得用绝对定位限制,防止影响到页面布局。将每一段用block展示,后续使用3d变换折叠起来。

// stylus
.outsideboxposition relativeheight 20px.loading-bar display flexposition absolutetransform-style preserve-3dheight 20px.blockheight 100%background #000f2e<div class="outsidebox" :style="{width: `${showWidth}px`}"><div class="loading-bar"><div class="block"></div></div>
</div>

建立主函数,接收参数为最终可视宽度

因折叠块起始是水平块,所以限制块个数为奇数,以横竖横方式生成。 艺术就是派大星! 随机数!块的宽度采用随机比值的方式生成,通过横向的比值和逆推实际总宽度。

const createRandomRatio = (num: number) => {// 创建随机比值,合为1let sum = 0;const numbers = [];for (let i = 0; i < num; i++) {let randomNumber = Math.random(); numbers.push(randomNumber);sum += randomNumber;}return numbers.map(num => num / sum);
}
const calcTotalWidht = (ratio: number[], width: number) => {// 根据用户输入宽度,反向求出折叠前宽度let r = 0;for(let i = 0; i < ratio.length; i+=2) {r += ratio[i];}let w = width / r;return w
}
const createRadomRect = (width: number) => {// 主函数入口,创建折叠矩形块let num = 11;let widthRatio = createRandomRatio(num); // 创建随机比值let calcW = calcTotalWidht(widthRatio, width); // 逆向推导实际宽度showWidth.value = width; // 用户看得到的宽度totalWidth.value = calcW; // 实际的宽度
}

实现创建横块与纵块

上一段获取到总宽度,接下来根据比值生成具体的块。

1.生成横块,返回横块的水平,垂直偏移位置

const createHorizontal = (id: number, horizontal: number, vertial: number, width: number) => {data.value.push({id,width,transform: `translateX(${horizontal}px) translateZ(${vertial}px)`})return {transX: horizontal,transZ: vertial}
}
  1. 接收横块位置,生成纵块位置,返回纵块水平位置及垂直位置
const createVertical = (id: number, horizontal: number, vertial: number, width: number) => {let direct = prevDirect.value == 1 ? -1 : 1; // 逆时针旋转则x右移z上移,顺时针则x右移z下移let transX = prevDirect.value * vertial + width / 2; // 如前一个旋转块方向相反则需更新垂直移动方向,前逆后顺更改为左移let transZ = horizontal * direct + width / 2 * -directdata.value.push({id,width,transform: `rotateY(${90 * direct}deg) translateZ(${transZ}px) translateX(${transX}px)`})prevDirect.value = direct;return {transX: horizontal + width * -1,transZ: vertial + width * -direct}
}
  1. 调整主函数,增加循环生成横纵块逻辑
const totalWidth = ref(0);
const showWidth = ref(0)
const data = ref([] as any)
const prevDirect = ref(1);
const createRadomRect = (width: number) => {// 主函数入口,创建折叠矩形块let num = 11;let widthRatio = createRandomRatio(num); // 创建随机比值let calcW = calcTotalWidht(widthRatio, width); // 逆向推导实际宽度showWidth.value = width; // 用户看得到的宽度totalWidth.value = calcW; // 实际的宽度let blockWidth = 0;let transX = 0;let transZ = 0;for(let i = 0; i < num; i++) {let rectWidth = Math.floor(calcW * widthRatio[i]);if(i == num - 1) {// 最后一个横块,修正floor带来的宽度缺失rectWidth = width - blockWidth} if(i % 2 == 0) {blockWidth += rectWidth;let obj = createHorizontal(i, transX, transZ, rectWidth)transX = obj.transX;transZ = obj.transZ;} else {let obj = createVertical(i,transX, transZ, rectWidth)transX = obj.transX;transZ = obj.transZ;}}
}

初具规模了,嘿嘿

 

实现进度动画

将进度抽象为0-1,对应的UI展示效果就是背景色的填充进度。因为是分块,所以将总体的宽度*进度,再分摊到每个块上进行显示。动画采用requestAnimationFrame API实现,懂得都懂。每步长度设置为0.001,这样看起来比较美观。

const progress = ref(0)
const calcChangeRect = (progress: number) => {// 计算每个矩形的进度let current = progress * totalWidth.value;let list = data.value;let add = 0;for(let i = 0; i < list.length; i++) {if(list[i].width + add > current) {list[i].progress = (current - add) / list[i].width;break} else {list[i].progress = 1;add += list[i].width;}}
}
const createAnimation = () => {let animationId = 0;let start = () => {progress.value += 0.001;if(progress.value < 1) {animationId = window.requestAnimationFrame(start)} else {progress.value = 1;window.cancelAnimationFrame(animationId);}calcChangeRect(progress.value)}animationId = window.requestAnimationFrame(start)
}

最后加点debugger工具

1.设置鼠标旋转事件

const rotateStyle = ref("")
const useMouseMove = ref(false)
const toggleMouseMove = () => {useMouseMove.value = !useMouseMove.value
}
const handleMouseMove =  (event: MouseEvent) => {if(!useMouseMove.value) return 0let pageX = event.pageX,pageY = event.pageY;const winW = window.innerWidth / 2,winH = window.innerHeight / 2;let X = 0;let Y = 0;if(pageX < winW) {X = -((winW - pageX) / winW * 90);} else {X = (pageX - winW) / winW * 90}if(pageY < winH) {Y = -((winH - pageY) / winH * 90);} else {Y = (pageY - winH) / winH * 90}rotateStyle.value = `transform: rotateY(${X}deg) rotateX(${Y}deg)`
}
document.addEventListener("mousemove", handleMouseMove);

2.设置主视图和45度视图

const setDisplay45 = () => {useMouseMove.value = false;rotateStyle.value = `transform: rotate3d(1, 1, 0, 45deg)`
}
const setDisplay0 = () => {useMouseMove.value = false;rotateStyle.value = ``
}

结语

这个项目是为了熟悉3d变换,在使用translateZ、translateX想了很久,脑子不够用了。还有很多地方可以调整为配置项,设置块数,块颜色等,甚至封装成api,下次一定。

本文转载于:https://juejin.cn/post/7370682158103347238

如果对您有所帮助,欢迎您点个关注,我会定时更新技术文档,大家一起讨论学习,一起进步。

 

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

excel 二级菜单联动筛选,减少筛选项,缓解打平之后筛选项过多不利于查看的问题

问题 二级菜单联动筛选,让标注更省力 步骤准备一级、二级菜单选项的映射表。公式 -> 根据所选内容创建准备一级下拉菜单选项。数据->数据验证->序列->选中区域准备二级下拉菜单选项。数据->数据验证->序列->公式(=INDIRECT(INDIRECT("C" &…

【Remotery】 Remotery-轻量级的远程实时 CPU/GPU 分析器设计浅析

1.Remotery简介 Remotery是一个轻量级的远程实时CPU/GPU分析器,主要用于监控CPU和GPU上多线程的活动。它提供了一个C文件,可以很容易的集成到项目中,并配置一个实时监控的Web界面,可以通过远程观察和分析程序的性能,适用于监控游戏的实时运行性能和分析移动端应用的性能场…

使用OpenCV进行ROS 2的循线跟踪

原文链接:https://www.youtube.com/watch?v=88y_1ovno8g In this Open Class, well explore how to implement a line-following robot using OpenCV and ROS 2. 在这堂公开课中,我们将探讨如何使用OpenCV和ROS 2来实现一个循线跟踪机器人。You will learn: ✏️ Introduct…

【Kernel】关于Linux内核参数 net.ipv4.ip_local_reserved_ports

网络端口号是如何分配的? 除了给常用服务保留的Well-known Port numbers之外,给客户端的端口号通常是动态分配的,称为ephemeral port(临时端口),在Linux系统上临时端口号的取值范围是通过这个内核参数定义的:net.ipv4.ip_local_port_range (/proc/sys/net/ipv4/ip_local_p…

LLM大模型:推理优化-vLLM显存使用优化

1、众所周知,transformer架构取得了巨大的成功,核心原因之一就是attention的引入。当年那篇论文的名称就叫attention is all you need,可见attention机制在transformer中的巨大作用!attention的计算示意图如下:同一个sequence中,每个token的q会和其他所有token的k求内积,…

sql拦截器的应用

问题:在实际开发当中,日志log的打印无法直接对sql层出现的问题进行整而概之的显示,使得开发中对sql层的具体变动无法直观的查看。当出现sql层方法报错后,需要不断地打log逐条分析错误,再进入sql层分析问题。 解决方案:利于mybatis的sql拦截器工具进行对sql的拦截以及日志…

vite+vue3+ts+pinis搭建项目框架

一:使用 vite 快速创建脚手架 1.创建新项目 命令行输入后,依次选择vue -> typescript。1 yarn create vite vite_vue3_typescript_pinia_template --template2.cd 到项目文件,安装依赖,启动项目1 # 进入项目文件夹 2 cd vite_vue3_typescript_pinia_template 3 # 安装依…

抖音私信卡片制作教程,使用W外链创建抖音/快手/小红书卡片

在数字营销和社交媒体日益繁荣的今天,利用外部链接(W外链平台)为抖音平台创建卡片已成为一种有效的推广手段。抖音卡片不仅可以直接将观众导向目标网页或产品,还能提高用户的参与度和品牌的曝光度。下面,我们将详细介绍如何使用W外链平台创建抖音卡片。 一、了解W外链平台…

GMSSL2.x编译鸿蒙静态库和动态库及使用

一、编译环境准备 1.1 开发工具 DevEco-Studio下载。 1.2 SDK下载 ​ 下载编译第三方库的SDK有两种方式,第一种方式从官方渠道根据电脑系统选择对应的SDK版本,第二种方式通过DevEco-Studio下载SDK。本文只介绍通过DevEco-Studio下载SDK的方式。安装SDK到本地根据SDK安装位置…

自定义测试器

测试器测试器总是返回一个布尔值,它可以用来测试一个变量或者表达式,使用”is”关键字来进行测试。{% set name=ab %} {% if name is lower %} <h2>"{{ name }}" are all lower case.</h2> {% endif %}测试器本质上也是一个函数,它的第一个参数就是待…

Invalid or unexpected token

异常:原因: js代码中可能符号错误,如括号没有关闭、半角全角、 本次的原因是双引号没有关闭

minix 文件系统

来自:https://in1t.top/2020/05/04/minix-1-0-%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F/ 下一个模块将是 fs(file system) 文件系统模块,在开始阅读源码之前,先对 Linux 0.11 中使用的 Minix 1.0 文件系统有个大致的概念,这对之后的代码阅读会有很大的帮助 文件系统是操作系统…