编译器:vscode
目的:为了实现商品到购物车的曲线运动,而模拟的一次小红点曲线运动
准备工作:实现小红点的曲线,需要一个公式(数学的曲线公式,物理的匀变速公式,贝塞尔曲线公式),我这儿使用的是贝塞尔曲线公式。
贝塞尔曲线算法可参考网址:贝塞尔曲线
代码
小红点运动
function init(i) {
let t = 0;
const p1 = [0, 0];
const cp = [600, 700];
const p2 = [1200, 0];
let redDot = document.createElement("div");
//为了对小红点实现模糊化,带有后缀,不要模糊化可自行更改类名
redDot.classList.add(`dot${i}`);
document.body.appendChild(redDot);
move();
function move() {
if(t > 1) {
document.body.removeChild(redDot);
return;
}
requestAnimationFrame(()=>{
let [newx, newy] = towBezier(t, p1, cp, p2);
redDot.style.left = newx + "px";
redDot.style.top = newy + "px";
t += 0.001;
move();
});
}
}
/*
* t为百分比,可以当作变量来实现小红点的运动
* p1为起点坐标
* p2为终点坐标
* cp为控制点坐标
*/
//二阶贝塞尔曲线,返回当前百分比所运动到的坐标点
function towBezier(t, p1, cp, p2) {
const [x1, y1] = p1;
const [cx, cy] = cp;
const [x2, y2] = p2;
let x = (1 - t) * (1 - t) * x1 + 2 * t * (1 - t) * cx + t * t * x2;
let y = (1 - t) * (1 - t) * y1 + 2 * t * (1 - t) * cy + t * t * y2;
return [x, y];
}
小红点模糊化
用类名不同实现透明度不同,来实现模糊化有后缀的感觉
//生成多个相同但出发时刻不同的点,目的为了生成残影
function manyDot() {
let i = 0;
let myadd = setInterval(() => {
if( i == 5) {
clearInterval(myadd);
return;
}
init(i);
i++;
}, 20);
}
css片段
* {
padding: 0;
margin: 0;
}
.dot0 {
width: 10px;
height: 10px;
background-color: red;
border-radius: 50%;
position: fixed;
}
.dot1 {
width: 10px;
height: 10px;
background-color: red;
border-radius: 50%;
position: fixed;
opacity: 0.5;
}
.dot2 {
width: 10px;
height: 10px;
background-color: red;
border-radius: 50%;
position: fixed;
opacity: 0.4;
}
.dot3 {
width: 10px;
height: 10px;
background-color: red;
border-radius: 50%;
position: fixed;
opacity: 0.3;
}
.dot4 {
width: 10px;
height: 10px;
background-color: red;
border-radius: 50%;
position: fixed;
opacity: 0.2;
}
完整代码
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>小球抛物线</title>
<style>
* {
padding: 0;
margin: 0;
}
.dot0 {
width: 10px;
height: 10px;
background-color: red;
border-radius: 50%;
position: fixed;
}
.dot1 {
width: 10px;
height: 10px;
background-color: red;
border-radius: 50%;
position: fixed;
opacity: 0.5;
}
.dot2 {
width: 10px;
height: 10px;
background-color: red;
border-radius: 50%;
position: fixed;
opacity: 0.4;
}
.dot3 {
width: 10px;
height: 10px;
background-color: red;
border-radius: 50%;
position: fixed;
opacity: 0.3;
}
.dot4 {
width: 10px;
height: 10px;
background-color: red;
border-radius: 50%;
position: fixed;
opacity: 0.2;
}
</style>
</head>
<body>
<script>
function init(i) {
let t = 0;
const p1 = [0, 0];
const cp = [600, 700];
const p2 = [1200, 0];
let redDot = document.createElement("div");
redDot.classList.add(`dot${i}`);
document.body.appendChild(redDot);
move();
function move() {
if(t > 1) {
document.body.removeChild(redDot);
return;
}
requestAnimationFrame(()=>{
let [newx, newy] = towBezier(t, p1, cp, p2);
redDot.style.left = newx + "px";
redDot.style.top = newy + "px";
t += 0.001;
move();
});
}
}
/*
* 二阶贝塞尔曲线
* t为当前百分比,根据t的变化曲线开始变化
* p1为起点坐标
* p2为终点坐标
* cp为控制点
*/
function towBezier(t, p1, cp, p2) {
const [x1, y1] = p1;
const [cx, cy] = cp;
const [x2, y2] = p2;
let x = (1 - t) * (1 - t) * x1 + 2 * t * (1 - t) * cx + t * t * x2;
let y = (1 - t) * (1 - t) * y1 + 2 * t * (1 - t) * cy + t * t * y2;
return [x, y];
}
//生成多个相同但出发时刻不同的点,目的为了生成残影
function manyDot() {
let i = 0;
let myadd = setInterval(() => {
if( i == 5) {
clearInterval(myadd);
return;
}
init(i);
i++;
}, 20);
}
manyDot();
</script>
</body>
</html>