1.应用场景 电商类的小程序
需求:在首页和分类页中,点击加入购物的小按钮之后,该商品的图片曲线运动至底部TabBar的购物车按钮中,运动时图片也在缩小
2.遇到的问题
1.曲线运动的路径
2.图片位置和点击区域的位置不一致
3.实现缩小动画
3.解决方案
1.用贝塞尔曲线获取运动的轨迹点,通过动画+setInterval来实现运动
在app.js中加入贝塞尔曲线计算方法
// 在app.js中加入贝塞尔曲线计算方法
/**
* 贝塞尔曲线
*/
bezier: function(points, part) {
let sx = points[0]['x'];
let sy = points[0]['y'];
let cx = points[1]['x'];
let cy = points[1]['y'];
let ex = points[2]['x'];
let ey = points[2]['y'];
var bezier_points = [];
// 起始点到控制点的x和y每次的增量
var changeX1 = (cx - sx) / part;
var changeY1 = (cy - sy) / part;
// 控制点到结束点的x和y每次的增量
var changeX2 = (ex - cx) / part;
var changeY2 = (ey - cy) / part;
//循环计算
for (var i = 0; i <= part; i++) {
// 计算两个动点的坐标
var qx1 = sx + changeX1 * i;
var qy1 = sy + changeY1 * i;
var qx2 = cx + changeX2 * i;
var qy2 = cy + changeY2 * i;
// 计算得到此时的一个贝塞尔曲线上的点
var lastX = qx1 + ((qx2 - qx1) * i) / part;
var lastY = qy1 + ((qy2 - qy1) * i) / part;
// 保存点坐标
var point = {};
point['x'] = lastX;
point['y'] = lastY;
bezier_points.push(point);
}
//console.log(bezier_points)
return {
'bezier_points': bezier_points
};
},
在组件中 js
// component/flyToCart/flyToCart.js
const app = getApp()
Component({
lifetimes: {
attached: function () {
// 获取屏幕宽度,以及TabBar数量,算出终点位置
this.endPos={};
this.endPos['x'] = (app.globalData.clientWidth / 10) * 6;
this.endPos['y'] = app.globalData.clientHeight;
},
detached: function () {
// 在组件实例被从页面节点树移除时执行
},
},
/**
* 组件的初始数据
*/
data: {
ani:null,
flag:true,//防止连续点击
},
/**
* 组件的方法列表
*/
methods: {
show(data) {
app.debugInfo('传入值',data)
if (!this.data.flag) return;
this.setData({
flag:false
})
let {
startPos,//初始位置
img//图片路径
}=data
this.setData({
imgUrl:img,
startPos
})
var topPoint = {};
// 计算最高点y坐标
if (startPos['y'] <= this.endPos['y']) {
topPoint['y'] = startPos['y'] - 150;
} else {
topPoint['y'] = this.endPos['y'] - 150;
}
// 计算最高点x坐标
if(startPos['x'] <= this.endPos['x']){
topPoint['x'] = (this.endPos['x'] - startPos['x']) / 2 + startPos['x']
}else {
topPoint['x'] = (startPos['x'] - this.endPos['x']) / 2 + this.endPos['x']
}
this.linePos = app.bezier([startPos, topPoint, this.endPos], 30);
// 缩小动画
this.scaleAnimation()
// 贝塞尔曲线动画
this.startAnimation();
},
startAnimation: function() {
var index = 0,
that = this,
bezier_points = that.linePos['bezier_points'];
this.setData({
bus_x: that.data.startPos.x,
bus_y: that.data.startPos.y
})
this.timer = setInterval(function() {
index++;
that.setData({
bus_x: bezier_points[index]['x'],
bus_y: bezier_points[index]['y']
})
if (index >= 28) {
clearInterval(that.timer);
app.debugInfo('time',index*33)
that.setData({
flag:true,
})
// 重置动画
that.scaleAnimation('originl')
}
}, 33);
},
scaleAnimation:function(type){
var animation = wx.createAnimation({
duration: 924, // 33*28
timingFunction: 'linear'
})
let that = this;
if (type =='originl'){
animation.scale(1).step();
this.setData({
ani: animation.export()
})
}else {
animation.scale(0).step();
this.setData({
ani: animation.export()
})
}
}
}
})
wxml文件
<view class="flyBox" hidden="{{flag}}" style="left: {{bus_x}}px; top: {{bus_y}}px;" animation="{{ani}}">
<image src="{{imgUrl}}" class="img"></image>
</view>
2.调用组件home.js中的加入购物车事件
//home.wxml
<!--图片位置-->
<view class="goods-image-tall" style="background-image:url('{{item.goodsListImg}}')" id="id{{item.goodsCode}}"></view>
<!-- 加入购物的按钮-->
<image catchtap="addGoods" data-goodsCode="{{item.goodsCode}}" data-type="RECOMEND_GOODS" data-goodsName="{{item.shopGoodsName}}" src='{{globalIcons.cart}}'
data-goods="{{item}}" data-from-type='{{0}}' lazy-load data-id="id{{item.goodsCode}}" data-img="{{item.goodsListImg}}"></image>
<!-- 飞入购物车动画 -->
<fly-to-cart id="fly"></fly-to-cart>
//home.js
//添加商品到购物车
addGoods(e) {
app.debugInfo('---加入购物车---',e)
let {
goodscode,
goodsname,
type,
optionList,
goods,
fromType,
id,
img
} = e.currentTarget.dataset
let that = this;
//判断用户是否登录
if (!app.globalData.token) {
wx.navigateTo({
url: '/pages/login/login',
})
} else {
// 判断是否商品是否需要加工
if (optionList && optionList.length > 0) {
app.globalData.byValue = goods; //传递商品信息
modalComponent = that.selectComponent('#cart-modal');
modalComponent.showCartAction(fromType);
} else {
this.setData({
dataType: type
})
let event = "ADD_TO_CART"
let data = {
"type": type,
"goodsCode": goodscode,
"goodsName": goodsname
}
dataPoint(event, data)
// 获取图片位置
fly = that.selectComponent('#fly'); // fly定义在home页面,页面卸载时记得清空
let query = that.createSelectorQuery();
query.select(`#${id}`).boundingClientRect();
query.exec(function (imgInfo) {
if (imgInfo[0]) {
app.debugInfo('图片位置信息', imgInfo)
fly.show({
img,
startPos:{
x: Number.parseInt(imgInfo[0].width / 2 + imgInfo[0].left),
y: Number.parseInt(imgInfo[0].height / 2 + imgInfo[0].top)
}
});
}
})
//不需要加工直接加入购物车
addToCart({
"goodsCode": goodscode, //商品编码
"num": 1 //商品数量
}).then(result => {
wx.showToast({
title: '加入购物车成功',
icon: 'none',
duration: 2000
})
countCartGoods()
}).catch(err => {
app.debugInfo("------ addCart failure -----", err)
})
}
}
},
最终效果: