看过很多文章,几乎都是JS计算,控制三个点实现,对我菜鸟的我来说太难了,我这边是用来position+CSS3 cubic-bezier() 函数,既然是分享,我会尽量贴完整代码,害,有的博客,没头没尾,不适合我这种菜鸡,希望能帮到需要的小伙伴
1、我这边不实现可以连续点击球体抛物线效果,通过定时器控制点击的频率,这个代码可以通用,没什么限制,不考虑IE啥的兼容鬼问题。
2、我是原生小程序,里面调用了 wx.createSelectorQuery().in(this).select(cls).boundingClientRect(rect => { }).exec();获取底部购物车的位置,如果是vue或者react 可以通过ref获取组件实例信息,这个具体看自己怎么调用了
WXML
<!-- 购物车添加-加号 -->
<view class="addImg_box" bindtap="handleAddFood" data-food="{{item}}">
<image class="img-add " src="{{fileUrl+'banner/details/add.png' }}" lazy-load="{{true}}"></image></view>
<!-- 购物车贝塞尔曲线运动,球体 -->
<view wx:if="{{ballDisplay}}" id="ball" style="top:{{ballTop}};left:{{ballLeft}}"></view>
<!-- tabbar栏 -->
<view class="position-tab">
<view class="tab-icon">
<view class="tab-icon-box">
<view class="tab-icon-item" bindtap="handleTabEvent" data-index="1">
<van-icon name="service" color="#515151" size="20px" />
<text class="text">客服</text>
</view>
<view class="tab-icon-item" id="tab-cart" bindtap="handleTabEvent" data-index="2">
<!-- 这是我的购物车图标位置,fiexd-cart-animate是购物车放大动画 -->
<van-icon class="{{cartScale?'fiexd-cart-animate':'' }}" name="cart" wx:if="{{!popupShow}}" color="#383637" size="20px" info="{{allIFoodNum}}" />
<van-icon name="cart" wx:else="{{popupShow}}" color="#ffd027" size="20px" info="{{allIFoodNum}}" />
<text class="text {{ popupShow?'tab_active':''}}">已选</text>
</view>
</view>
</view>
<view class="tab-subscribe">立即预约
<view class="tab-bottom">
<button hover-class="button-active" class="tab-bottom-btn" open-type="getUserInfo" bindgetuserinfo="handlePurchase"></button>
</view>
</view>
</view>
CSS
/* 购物车抛物线 这里只涉及球体的css,贝塞尔曲线动画的css,还有购物车放大的效果,其他布局自由发挥 */
#ball{
position: fixed;
width:30rpx;
height:30rpx;
background-color: red;
border-radius: 50%;
z-index:99999 !important;
/* cubic-bezier(.27,-.27,.36,1.04) 这个是关键css代码,第二个值是负数,实现回弹效果,具体自己调试 */
transition: 0.5s top cubic-bezier(.27,-.27,.36,1.04), 0.5s left cubic-bezier(.29,.68,.64,1);
}
.fiexd-cart-animate{
animation: aCartScale 300ms cubic-bezier(.17,.67,.83,.67);
animation-fill-mode: backwards;
}
@keyframes aCartScale{
0%{
-webkit-transform: scale(1.15);
}
100% {
-webkit-transform: scale(1);
}
}
JS部分
data:{
ballDisplay: false,//控制球体显示
ballTop: 100,//球体的top值
ballLeft: 0,//球体的left值
originTop: 0,//保留原位置top,其实可以简化掉,暂时不操作,小伙伴看着来
originLeft: 0,//保留原位置left
start: false,//控制点击购物的频率
cartScale: false,//控制点击购物车的放大效果
}
//购物车添加事件,部分JS是我的业务逻辑
handleAddItemFood(e) {
console.log(e, '添加事件对象');
//传入当前点击位置的 x y值,起点,封装的函数里面通过wx.createSelectorQuery()获取 购物车图标的重点位置
let eObj = {
x: e.touches["0"].clientX,//相对于可视区域的值
y: e.touches["0"].clientY
}
// 禁止动画多次触发
if (this.data.start) {
return;
}
//当执行完动画效果,再实现购物车图标角标的值计算,当调用完 this.setAnimationBall(eObj),说明动画已经执行完毕
this.setAnimationBall(eObj).then(() => {
let obj = e.currentTarget.dataset.food;
let arr = this.data.checkFoodsItem;
if (arr.length > 0) {
let index = this.data.checkFoodsItem.findIndex(v => v.ID === obj.ID);
if (index == -1) {
arr.push(obj)
} else {
arr[index].num++
}
} else {
arr.push(obj)
}
this.setData({
checkFoodsItem: arr
})
this.chcekComputed()
})
},
// 购物车抛物线事件封装--------------
// 获取节点信息-原生小程序的api
getRects(cls) {
return new Promise((resolve, reject) => {
wx.createSelectorQuery().in(this).select(cls).boundingClientRect(rect => {
resolve(rect);
}).exec();
});
},
// 初始化球体的位置
initBallPos() {
this.setData({
ballTop: `${100}px`,
ballLeft: `${270}px`,
originTop: `${100}px`,
originLeft: `${270}px`
});
},
//购物车添加事件的球体动画,promise封装是为了球体到了购物车再实现角标数量添加的效果
setAnimationBall(parmas) {
return new Promise((resolve, reject) => {
//防止多次触发
this.data.start = true;
//再次初始化 球体点击的当前位置,具体自己根据情况修改值
this.setData({
ballTop: `${parmas.y - 10}px`,
ballLeft: `${parmas.x - 5}px`,
originTop: `${parmas.y - 10}px`,
originLeft: `${parmas.x -5}px`,
cartScale: false,
ballDisplay: true
});
// 获取小球终点位置
this.getRects("#tab-cart").then(rect => {
console.log(rect, '小球终点位置');
let left = Math.floor(rect.left) + Math.floor(rect.width / 2) - 5;
let top = Math.ceil(rect.top)
this.setData({
ballTop: `${top +5}px`,
ballLeft: `${left}px`
});
// 定时器延时跟动画时长一致,飞完隐藏掉,再把小球重置到初始位置。
let {
originLeft,
originTop
} = this.data;
setTimeout(() => {
this.setData({
ballDisplay: false,
ballTop: originTop,
ballLeft: originLeft,
start: false,//放开频率
cartScale: true,//球体到购物车图标时,图标放大效果
});
resolve()
}, 500);
});
})
},
//初始化球体的位置
onReady: function () {
this.initBallPos()
},
效果图,小弟不会搞gif。。然后就是这样效果