1、效果图:
2、创建子组件canvas_love.vue
<template>
<view class="action">
<view class="icon_img">
<view class="icon_smallimg"></view>
<view class="texttag">限时5折起</view>
<canvas canvas-id="mycanvas" class="canvas" />
</view>
</view>
</template>
<script>
var lastFrameTime = 0;
var count = 0;
var ctx = null;
var factor = {
speed: 0.004, // 运动速度,值越小越慢
t: 0 // 贝塞尔函数系数
};
var that;
var timer = null; // 循环定时器
export default {
name: 'canvas_love',
data() {
return {
style_img: '',
img_path: [
[{
x: 30,
y: 50
}, {
x: 40,
y: 30
}, {
x: 60,
y: 25
}, {
x: 40,
y: 0
}],
[{
x: 30,
y: 50
}, {
x: 70,
y: 20
}, {
x: 80,
y: 10
}, {
x: 30,
y: 0
}],
[{
x: 30,
y: 50
}, {
x: 60,
y: 10
}, {
x: 70,
y: 0
}, {
x: 20,
y: 0
}]
]
}
},
created() {
that = this
//获取canvas实例
ctx = uni.createCanvasContext('mycanvas', this)
},
mounted() {
//一直循环: repeatcount 为-1的情况
that.startTimer(-1)
// console.log("挂载完成,可以拿到属性", ctx);
},
destroyed() {
if (timer != null) {
clearTimeout(timer)
}
},
methods: {
//不断绘制图片到canvas;requestAnimationFrame函数用来控制动画的时间长短
requestAnimationFrame(callback) {
var currTime = new Date().getTime();
//手机屏幕刷新率一般为60Hz,大概16ms刷新一次,这里为了使页面看上去更流畅自然,通过改变timedis的值可以控制动画的快慢
var timedis = 16 - (currTime - lastFrameTime)
var timeToCall = Math.max(0, timedis);
var id = setTimeout(callback, timeToCall);
lastFrameTime = currTime + timeToCall;
return id;
},
drawImage: function(data, repeatcount) {
if (repeatcount == 0) {
return
}
var p10 = data[0][0]; // 三阶贝塞尔曲线起点坐标值
var p11 = data[0][1]; // 三阶贝塞尔曲线第一个控制点坐标值
var p12 = data[0][2]; // 三阶贝塞尔曲线第二个控制点坐标值
var p13 = data[0][3]; // 三阶贝塞尔曲线终点坐标值
var p20 = data[1][0];
var p21 = data[1][1];
var p22 = data[1][2];
var p23 = data[1][3];
var p30 = data[2][0];
var p31 = data[2][1];
var p32 = data[2][2];
var p33 = data[2][3];
var t = factor.t;
/*计算多项式系数*/
var cx1 = 3 * (p11.x - p10.x);
var bx1 = 3 * (p12.x - p11.x) - cx1;
var ax1 = p13.x - p10.x - cx1 - bx1;
var cy1 = 3 * (p11.y - p10.y);
var by1 = 3 * (p12.y - p11.y) - cy1;
var ay1 = p13.y - p10.y - cy1 - by1;
/*计算xt yt坐标值 */
var xt1 = ax1 * (t * t * t) + bx1 * (t * t) + cx1 * t + p10.x;
var yt1 = ay1 * (t * t * t) + by1 * (t * t) + cy1 * t + p10.y;
/** 计算多项式系数*/
var cx2 = 3 * (p21.x - p20.x);
var bx2 = 3 * (p22.x - p21.x) - cx2;
var ax2 = p23.x - p20.x - cx2 - bx2;
var cy2 = 3 * (p21.y - p20.y);
var by2 = 3 * (p22.y - p21.y) - cy2;
var ay2 = p23.y - p20.y - cy2 - by2;
/*计算xt yt坐标值*/
var xt2 = ax2 * (t * t * t) + bx2 * (t * t) + cx2 * t + p20.x;
var yt2 = ay2 * (t * t * t) + by2 * (t * t) + cy2 * t + p20.y;
/** 计算多项式系数*/
var cx3 = 3 * (p31.x - p30.x);
var bx3 = 3 * (p32.x - p31.x) - cx3;
var ax3 = p33.x - p30.x - cx3 - bx3;
var cy3 = 3 * (p31.y - p30.y);
var by3 = 3 * (p32.y - p31.y) - cy3;
var ay3 = p33.y - p30.y - cy3 - by3;
/*计算xt yt坐标值*/
var xt3 = ax3 * (t * t * t) + bx3 * (t * t) + cx3 * t + p30.x;
var yt3 = ay3 * (t * t * t) + by3 * (t * t) + cy3 * t + p30.y;
factor.t += factor.speed;
ctx.drawImage("/static/images/love1.png", xt1, yt1, 20, 20);
ctx.drawImage("/static/images/love2.png", xt2, yt2, 14, 14);
ctx.drawImage("/static/images/love3.png", xt3, yt3, 8, 8);
ctx.draw();
if (factor.t > 1) {
factor.t = 0;
clearTimeout(timer)
if (repeatcount <= -1) {
that.startTimer(repeatcount)
} else {
if (count < repeatcount) {
that.startTimer(repeatcount)
count++
} else {
that.draworiginal()
count = 0;
}
}
} else {
timer = that.requestAnimationFrame(function() {
that.drawImage(that.img_path, repeatcount)
})
}
},
//适用于不循环时设置点击事件触发动画
onClickImage: function(e) {
//点击心形的时候动画效果
// that.style_img = 'transform: scale(1);'
// setTimeout(function() {
// that.style_img = 'transform:scale(1);'
// }, 500)
factor.t = 2
count = 0
that.startTimer(-1)
},
//repeatcount -1就是循环,其他大于零的整数就是动画循环次数
startTimer: function(repeatcount) {
that.drawImage(that.img_path, repeatcount)
},
//draworiginal函数将图片都画到原始位置
draworiginal() {
ctx.drawImage("/static/images/love1.png", 30, 50, 30, 30);
ctx.drawImage("/static/images/love2.png", 30, 50, 30, 30);
ctx.drawImage("/static/images/love3.png", 30, 50, 30, 30);
ctx.draw();
}
}
}
</script>
<style lang="scss">
.canvas {
background: transparent;
width: 180rpx;
height: 100rpx;
position: absolute;
bottom: 32rpx;
left: 60rpx;
display: flex;
flex-direction: column;
align-items: flex-end;
}
.action {
margin-top: 150rpx;
margin-left: 100rpx;
}
.icon_img {
background-image: url('@/static/images/wzd.png');
background-repeat: no-repeat;
background-size: 100% auto;
/* #ifdef H5 */
width: 180rpx;
height: 38rpx;
/* #endif */
/* #ifndef H5 */
width: 170rpx;
height: 32rpx;
/* #endif */
display: flex;
align-items: center;
justify-content: center;
position: relative;
top: 0;
left: 0;
transform: scale(1);
-webkit-transform: scale(1);
-webkit-transition: ease all;
-moz-transition: ease all;
transition: ease all;
-webkit-transition-duration: 700ms;
-moz-transition-duration: 700ms;
transition-duration: 700ms;
}
.icon_smallimg {
background-image: url('@/static/images/5z.png');
background-repeat: no-repeat;
background-size: 100% auto;
width: 30rpx;
height: 24rpx;
}
.texttag {
// width: 84rpx;
height: 32rpx;
line-height: 32rpx;
margin-left: 10rpx;
font-size: 22rpx;
font-weight: 400;
color: #FFFFFF;
display: flex;
align-items: center;
}
</style>
3、父组件中引入、注册并使用
<template>
<view class="often">
<!-- 常用组件库 -->
<canvas-love></canvas-love>
</view>
</template>
<script>
import canvasLove from './components/canvas_love.vue'
export default {
components: {
canvasLove
},
data() {
return {
}
},
onShow() {
},
methods: {
}
}
</script>
<style lang="scss">
</style>
4、注:h5正常但微信小程序失效(代码已处理)
新版本的uni-app要求传入当前this对象
uni.createCanvasContext('mycanvas', this)