原生 JavaScript 实现 Win8 风格旋转圆圈进度条
通过面向对象设计与三角函数坐标计算,使用原生 JavaScript 实现类似 Windows 8 风格的旋转加载进度条,包含完整的源码与运行原理说明。
实现原理概述
该进度条的实现主要依赖以下三个核心技术点:
- 面向对象封装:将每个运动的“圆点”抽象为一个
ProgressBarWin8类,管理其自身的样式、位置、角度和定时器状态。 - 三角函数定位:利用正弦(
Math.sin)和余弦(Math.cos)函数,根据当前角度和半径实时计算圆点在 X/Y 轴上的像素坐标。 - 动态定时器延迟:通过判断圆点当前所在的水平位置(相对于圆心),动态调整
setTimeout的延迟毫秒数,从而模拟出加速(左侧慢)和减速(右侧快)的物理惯性效果。
核心逻辑与参数说明
第1步:定义圆点类结构与样式
首先需要建立圆点的“模板”,规定其半径、颜色、大小以及默认的运动初始角度。
radius: 圆的半径,决定轨道大小。angle: 起始角度,默认为 270 度(对应圆周上方)。style: CSS 样式集合,注意必须设置position: absolute才能通过修改left/top属性来移动元素。
第2步:数学公式映射坐标
在浏览器中,圆形的轨迹计算需将角度转换为弧度。公式如下:
X 轴坐标 = cos(弧度) * 半径 + 圆心X
Y 轴坐标 = sin(弧度) * 半径 + 圆心Y
其中弧度计算公式为:Math.PI * 角度 / 180。
第3步:运动循环与速度调节
这是产生视觉动感的关键。代码逻辑如下:
// 每次调用 run 方法时更新角度
this.angle++;
// 判断当前位置与圆心水平关系的偏移
if (this.position.left < this.fixed.left) {
// 左半区:增加延迟,模拟减速/起步阻力
this.delay += 0.5;
} else {
// 右半区:减少延迟,模拟加速/重力势能转化
this.delay -= 0.5;
}
// 再次执行 run,形成递归式循环
this.timer = setTimeout(() => {
scope.run();
}, this.delay);
完整源代码实现
以下是整合后的完整 HTML/JS 代码,可直接保存为 .html 文件在浏览器中运行。
复制代码
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>仿win8等待进度条</title>
<style>
body {
margin: 0;
padding: 0;
background: #333; /* 深色背景使白色圆点更明显 */
overflow: hidden;
}
</style>
</head>
<body>
<script>
/*
* 准备条件:
* 弧度角度转换公式:弧度=Math.PI*角度/180;
* 圆x轴坐标: Math.cos(Math.PI * 角度/ 180) * 半径 + 圆心x
* 圆y轴坐标: Math.sin(Math.PI * 角度/ 180) * 半径 + 圆心y
*/
// 圆点元素类
function ProgressBarWin8() {
this.fixed = { left: 0, top: 0 }; // 圆心相对屏幕坐标
this.position = { left: 0, top: 0 }; // 当前圆点坐标
this.radius = 70; // 圆半径
this.angle = 270; // 起始角度(顶部)
this.delay = 30; // 基础定时器延迟
this.timer = null;
this.dom = null;
// 圆点样式配置
this.style = {
position: "absolute",
width: "10px",
height: "10px",
background: "#fff",
"border-radius": "5px"
};
}
ProgressBarWin8.prototype = {
// 运动主方法
run: function() {
if (this.timer) clearTimeout(this.timer);
// 1. 重新计算坐标
this.position.left = Math.cos(Math.PI * this.angle / 180) * this.radius + this.fixed.left;
this.position.top = Math.sin(Math.PI * this.angle / 180) * this.radius + this.fixed.top;
// 2. 应用样式
this.dom.style.left = this.position.left + "px";
this.dom.style.top = this.position.top + "px";
// 3. 角度递增
this.angle++;
// 4. 动态调整速度(关键特效逻辑)
if (this.position.left < this.fixed.left) {
this.delay += 0.5;
} else {
this.delay -= 0.5;
}
var scope = this;
// 5. 延迟执行
this.timer = setTimeout(function () {
scope.run();
}, this.delay);
},
// 初始化 DOM 与位置
defaultSetting: function () {
this.dom = document.createElement("span");
for (var property in this.style) {
this.dom.style[property] = this.style[property];
}
// 定位到屏幕中心
this.fixed.left = window.innerWidth / 2;
this.fixed.top = window.innerHeight / 2;
// 计算并放置初始位置
this.position.left = Math.cos(Math.PI * this.angle / 180) * this.radius + this.fixed.left;
this.position.top = Math.sin(Math.PI * this.angle / 180) * this.radius + this.fixed.top;
this.dom.style.left = this.position.left + "px";
this.dom.style.top = this.position.top + "px";
document.body.appendChild(this.dom);
return this;
}
};
// 全局变量
var progressArray = []; // 存储生成的圆点对象
var tempArray = []; // 辅助重置数组
var timer = 200; // 间隔多少毫秒生成一个圆点
// 创建圆点对象实例
for (var i = 0; i < 5; ++i) {
progressArray.push(new ProgressBarWin8().defaultSetting());
}
// 数组扩展each方法,用于统一处理数组内对象的属性重置
Array.prototype.each = function (fn) {
for (var i = 0, len = this.length; i < len;) {
fn.call(this[i++], arguments);
}
};
// 窗口尺寸改变时,更新所有圆点的圆心坐标以居中
window.onresize = function () {
tempArray.each(function () {
this.fixed.left = window.innerWidth / 2;
this.fixed.top = window.innerHeight / 2;
});
};
// 启动动画引擎:定时从队列取出一个对象开始运行
var startTimer = setInterval(function () {
if (progressArray.length <= 0) {
clearInterval(startTimer);
} else {
var entity = progressArray.shift();
tempArray.push(entity); // 存入暂存区以便resize重算
entity.run(); // 开始运动
}
}, timer);
</script>
</body>
</html>
总结
本方案通过纯原生 JavaScript 实现了轻量级的加载动画,未依赖任何第三方库。其优势在于对数学坐标系的理解以及对定时器精度控制的灵活应用,适用于需要自定义加载效果的非重型业务场景。 以上就是原生javascript模仿win8等待提示圆圈进度条的详细内容,更多关于javascript动画资料请关注本站其它相关文章!
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













