这是我参与8月更文挑战的第 4 天,活动详情查看: 8月更文挑战
老规矩,先点赞在查看,谢谢
描述
最近要实现一个抛物线运动到指定地点,然后喷发更多的抛物线运动,其实就像烟花一样的效果
思路
- 刚开始,我本来想走css动画的路线的,因为css使用
animate做动画,对浏览器性能会有好很多,特别是这些抛物线多且长,一直执行渲染的话,对浏览器确实不太友好。 - 寻找了许久,发现贝塞尔曲线在css中使用只是控制运动物体的速度,并不是用来控制物体的抛物线的,这就让我痛苦万分,如果想要使用css做一个抛物线运动,那我们只能使用2个div去实现,css实现的思路:2个div,一个父级,一个子级,2个元素都要绑定过渡动画属性
transition: all 2s cubic-bezier(0,1.26,.51,1.35);,添加后就让他运动起来,运动的话其实要使用transform: translateX(100px)进行左右移动,分别给父级向上位移,给子元素向下移动,然后就形成了抛物线的卑微效果。 - 主角
- 使用css效果好像并不能达到我想要的效果,并且要控制运动也不容易,于是百度一番,找到了一个新的方法,就是使用贝塞尔曲线运动画路径的方法js贝塞尔曲线路径点,写的不错,并且直接使用就可以了,曲线计算方法如下:(说实话,我看不懂,数学的奥秘)
- 具体使用方法很简单,你想要画什么曲线都可以,只需要把坐标位置写上去,然后就会遍历出密密麻麻的点,连接起来就是你想要的曲线轨迹,此公式威力巨大。
代码
- 首先我们来看看公式转换成代码后,是怎样写的 (以下是共用函数,接下来的例子我不重复写了,你们记得要引入)
//anchorpoints:贝塞尔基点
//pointsAmount:生成的点数
//return 路径点的Array
function CreateBezierPoints(anchorpoints, pointsAmount) {
var points = [];
for (var i = 0; i < pointsAmount; i++) {
var point = MultiPointBezier(anchorpoints, i / pointsAmount);
points.push(point);
}
return points;
}
function MultiPointBezier(points, t) {
var len = points.length;
var x = 0, y = 0;
var erxiangshi = function (start, end) {
var cs = 1, bcs = 1;
while (end > 0) {
cs *= start;
bcs *= end;
start--;
end--;
}
return (cs / bcs);
};
for (var i = 0; i < len; i++) {
var point = points[i];
x += point.x * Math.pow((1 - t), (len - 1 - i)) * Math.pow(t, i) * (erxiangshi(len - 1, i));
y += point.y * Math.pow((1 - t), (len - 1 - i)) * Math.pow(t, i) * (erxiangshi(len - 1, i));
}
return { x: x, y: y };
}
- 知道怎么一个函数,然后我们来画一条长长的抛物线,固定2点,画起来
<div>
<div id="move_div" ref="flagMove"
style=" position: absolute; left: 0px; top: 0px; height: 10px; width: 10px; background-color: red;"
></div>
<div
v-for="item in flagPoint" :key="item.x" :style="'left:' + item.x + 'px;' + 'top:' + item.y + 'px;'"
style="position: absolute; width: 2px; height: 2px; overflow: hidden; background-color: #ff0000;"
></div>
</div>
data() {
return {
flagPoint: [],
flagCss: {},
}
},
mounted() {
this.startFlag();
},
methods: {
startFlag() {
let that = this;
let flagPoint = this.flagPoint;
let index = 0;
let ps = [
{ x: 100, y: 800 },
{ x: 200, y: 400 },
{ x: 500, y: 100 },
{ x: 800, y: 200 },
{ x: 1000, y: 350 },
];
flagPoint = CreateBezierPoints(ps, 800);
let moveobj = this.$refs.flagMove;
console.log(moveobj, "moveobj");
let timer = setInterval(function () {
let p = flagPoint[index];
// console.log(p.x);
moveobj.style.left = p.x + "px";
moveobj.style.top = p.y + "px";
// moveobj.css({ left: p.x, top: p.y });
index++;
if (index >= flagPoint.length) {
index = 0;
clearInterval(timer);
}
}, 1000 / 100);
this.flagPoint = flagPoint;
},
渲染出来的效果图:
- 当运动点到顶端后,我们就开始画烟花一样的效果了,只是多调一下封装好的函数而已,简单直接上代码
<div>
<div :id="'move_div'+index" v-for="(item, index) in signList" :key="index" :ref="'sign' + index"
style="position: absolute; left: 0px; top: 0px; height: 10px; width: 10px; background-color: red;"
></div>
<div v-for="(item, index) in guijiPointList" :key="index">
<div v-for="(items) in item" :key="items.x" :style="'left:' + items.x + 'px;' + 'top:' + items.y + 'px;'"
style="position: absolute; width: 2px; height: 2px; overflow: hidden; background-color: #ff0000;"
></div>
</div>
</div>
data() {
return {
signList: [
[
{ x: 1000, y: 350 },
{ x: 1000, y: 200 },
{ x: 1100, y: 150 },
{ x: 1050, y: 120 },
{ x: 1000, y: 100 },
],
[
{ x: 1000, y: 350 },
{ x: 1000, y: 200 },
{ x: 1030, y: 250 },
{ x: 1050, y: 220 },
{ x: 1100, y: 200 },
],
[
{ x: 1000, y: 350 },
{ x: 1000, y: 200 },
{ x: 1050, y: 220 },
{ x: 1100, y: 250 },
{ x: 1200, y: 300 },
],
[
{ x: 1000, y: 350 },
{ x: 1000, y: 200 },
{ x: 1100, y: 250 },
{ x: 1200, y: 300 },
{ x: 1300, y: 400 },
],
[
{ x: 1000, y: 350 },
{ x: 1000, y: 200 },
{ x: 1050, y: 300 },
{ x: 1100, y: 400 },
{ x: 1150, y: 450 },
],
[
{ x: 1000, y: 350 },
{ x: 1000, y: 200 },
{ x: 950, y: 400 },
{ x: 900, y: 500 },
{ x: 1000, y: 600 },
],
[
{ x: 1000, y: 350 },
{ x: 1000, y: 200 },
{ x: 950, y: 250 },
{ x: 900, y: 300 },
{ x: 800, y: 400 },
],
[
{ x: 1000, y: 350 },
{ x: 1000, y: 200 },
{ x: 850, y: 250 },
{ x: 700, y: 280 },
{ x: 600, y: 300 },
],
[
{ x: 1000, y: 350 },
{ x: 1000, y: 200 },
{ x: 900, y: 250 },
{ x: 750, y: 220 },
{ x: 650, y: 200 },
],
[
{ x: 1000, y: 350 },
{ x: 1000, y: 200 },
{ x: 900, y: 220 },
{ x: 800, y: 150 },
{ x: 700, y: 100 },
],
[
{ x: 1000, y: 350 },
{ x: 1000, y: 200 },
{ x: 980, y: 220 },
{ x: 950, y: 150 },
{ x: 900, y: 100 },
],
],
guijiPointList: []
};
},
methods: {
morePoint() {
let that = this;
let ps1 = this.signList;
ps1.forEach(function (obj, i) {
console.log(obj, "obj", i);
that.signPoint(obj, i);
});
},
signPoint(data, i) {
// console.log(data, "data");
let flagPoint = [];
let index = 0;
let ps = data;
flagPoint = CreateBezierPoints(ps, 500);
this.guijiPointList.push(flagPoint);
let moveobj = this.$refs[`sign${i}`][0];
if(!moveobj) return;
let timer = setInterval(function () {
let p = flagPoint[index];
moveobj.style.left = p.x + "px";
moveobj.style.top = p.y + "px";
// moveobj.css({ left: p.x, top: p.y });
index++;
if (index >= flagPoint.length) {
index = 0;
clearInterval(timer);
}
}, 1000 / 100);
},
}
最好得到的效果就是如下:
总结
注意这里需要说明下,坐标点是可以自己增加或减少的,看轨迹需要来增减吧,我这边只是做个大概效果,具体更好看的效果只能自己动手丰衣足食了