一、核心代码
1)wxml 核心代码
<canvas wx:for="{{bezierCount-0}}" wx:key="key" class="heart-center" canvas-id="bezier{{index}}"
style="width:{{width}}px;height:{{height}}px;"></canvas>
<view class="love-new heart" bindtap="bubbleAnimate" style="margin-left:325rpx;margin-top:{{margintop}}px">
<view class="" style="font-size:{{heartsize}}rpx;color:{{heartcolor}}">❤</view>
<!-- 这个爱心自己换上字体或者图片爱心 -->
</view>
2)wxss代码
.love-new {
width: 100rpx;
height: 100rpx;
/* z-index: 1024; */
opacity: 0.8;
border-radius: 100rpx;
display: flex;
align-items: center;
justify-content: center;
}
.heart{
border: 1px solid #ff3434;
box-shadow: 0rpx 0rpx 6rpx #ff3434;
color: #ff3434;
}
.like-fx {
pointer-events: none;
}
.second
{
width:300rpx;
height:800rpx;
display: inline-block;
}
.heart-center
{
position: absolute;
opacity: 1;
}
3)js核心代码:采用三阶贝塞尔曲线控制爱心路线;通过改变t值控制爱心的移动速度;设置画布的透明度 (ctx.globalAlpha)实现慢慢模糊效果;到达阶贝塞尔曲线的终点清理画布(ctx.draw()),爱心消失。
bubbleAnimate: function () {
var that=this;
let num = 0;
let XLeft=[that.starX-that.data.width/6,that.starX-that.data.width/3]
let XRight=[that.starX+that.data.width/6,that.starX+that.data.width/3]
let YPath=[that.startY-that.data.height/3,that.startY-that.data.height*2/3];
timeSenter = setInterval(() => {
//#region 设置按钮心心的大小和颜色
this.setData({
heartsize: sizeList[num % sizeList.length],
heartcolor: colorList[num % colorList.length]
});
//#endregion
//#region 使心心每次移动轨迹为左右对称
var xpoint=XLeft[0];
var xpoint=XLeft[1];
var endX=this.getRandom(0,that.data.width/2)
if(num%2==1)
{
xpoint=XRight[0];
xpoint=XRight[1];
endX=this.getRandom(that.data.width/2,that.data.width,)
}
//#endregion
//60=width/2/2-heartwidth/2
let anitPath1 = [{ x: that.starX, y: that.startY }, { x:xpoint, y: YPath[0] }, { x: xpoint, y: YPath[1] }, { x: endX, y: 0 }];
let factor={
speed: 0.003, // 运动速度,值越小越慢
t: 0, // 贝塞尔函数系数
opacity:1
}
var imgnum=num%24+1;
let data = { factor: factor, image: "../../../image/hearts/" + imgnum + ".png", path: anitPath1, num: num, count: 0 }
let ctx1 = wx.createCanvasContext("bezier" + num, this);
this.rawImage(data, true, ctx1);
if (num ==this.data.bezierCount) {
clearInterval(timeSenter);
}
num++;
}, 500);
},
getRandom: function (min, max) {
return Math.random() * (max - min) + min;
},
rawImage: function (data,first,ctx1,timer1) {
let path=data.path;
var that = this
var p10 = path[0]; /* 三阶贝塞尔曲线起点坐标值*/
var p11 = path[1]; /* 三阶贝塞尔曲线第一个控制点坐标值*/
var p12 = path[2]; /* 三阶贝塞尔曲线第二个控制点坐标值*/
var p13 = path[3]; /* 三阶贝塞尔曲线终点坐标值*/
var t = data.factor.t;
if (data.factor.t >= 0.5) {
//变速,先快后慢
t-=0.001;
}
/*计算多项式系数 (下同)*/
const x1 = p10.x * Math.pow(1 - t, 3) + 3 * p11.x * t * Math.pow(1 - t, 2) + 3 * p12.x * Math.pow(t, 2) * (1 - t) + p13.x * Math.pow(t, 3);
const y1 = p10.y * Math.pow(1 - t, 3) + 3 * p11.y * t * Math.pow(1 - t, 2) + 3 * p12.y * Math.pow(t, 2) * (1 - t) + p13.y * Math.pow(t, 3);
var curAlpha = data.factor.opacity;
curAlpha =y1 /that.data.height+0.3;
curAlpha = Math.min(1, curAlpha);
ctx1.globalAlpha = curAlpha;
let img = data.image;
ctx1.drawImage(img, x1, y1, 30, 30);
data.factor.t += data.factor.speed;
data.count++;
ctx1.draw();
if (data.factor.t >= 1) {
data.factor.t = 0;
that.cancelAnimationFrame(ctx1,timer1);
data.count=0;
} else {
timer1 =this.requestAnimationFrame(function () {
that.rawImage(data,false,ctx1,timer1)
})
}
},
cancelAnimationFrame: function (ctx1,timer1) {
clearTimeout(timer1);
ctx1.draw(); // 清空画面
},
requestAnimationFrame:function(load){
setTimeout(() => {
load();
}, 5);
},
二、效果图展示,扫描下方小程序码查看动态效果图
三、想看更多效果请搜索微信小程序“简单学习吧”,即可体验点击旋转抽奖效果,小程序还有其他画布效果,持续更新中