加入购物车动画首先需要获取到动画元素的初始位置和到达位置,利用props传参获得
const props = withDefaults(defineProps<Props>(), {
inDomStyle: () => ({
left: 0,
top: 0,
}),
toDomStyle: () => ({
left: 0,
top: 0,
}),
ballImg: '',
})
页面结构
<template>
<view v-for="(item, index) in ballList" :key="index">
<view class="Ball" :style="item.ballStyle">
<view class="inner" :style="item.ballInnerStyle">
<uv-image :src="item.img" width="60rpx" height="60rpx" mode="aspectFit" radius="30rpx">
<template v-slot:error>
<view style="font-size: 24rpx">加载失败</view>
</template>
</uv-image>
</view>
</view>
</view>
</template>
监听用户点击,去触发获取小球的初始位置信息和图片添加到ballList中创建出一个小球
watch(
() => props.ballImg,
() => {
console.log('收到的值,', props.inDomStyle, props.toDomStyle)
addBall()
},
)
addBall函数,将小球的初始位置和图片传到ballList中,并触发addCart加入购物车函数中
const addBall = () => {
ballList.value.push({
ballStyle: {
left: `${props.inDomStyle.left}px`,
top: `${props.inDomStyle.top}px`,
},
ballInnerStyle: {
left: '0px',
},
img: props.ballImg,
// InnerStyleTop: `${props.toDomStyle.left - props.inDomStyle.left}`
})
addCart(ballList.value.length - 1)
}
addCart函数,利用异步将小球的位置由初始位置变成抵达位置,后将小球隐藏,在动画事件后触发小球隐藏,并返回动画结束,也可以不需要隐藏,将购物车层级比小球高即可
const addCart = (index) => {
// 利用异步将其dom动画开始
toInDom(index).then((res) => {
setTimeout(() => {
showBall.value = false
emit('animationEnd')
}, 1000)
})
}
const toInDom = (index) => {
console.log(props.toDomStyle.left, props.inDomStyle.left, '12344')
return new Promise((resolve) => {
setTimeout(() => {
ballList.value[index].ballInnerStyle.left = `${
props.toDomStyle.left - props.inDomStyle.left
}px`
ballList.value[index].ballStyle.top = `${props.toDomStyle.top}px`
resolve(true)
}, 10)
})
}
css想要做抛物线需要利用两个dom元素,一个向垂直移动一个向水平移动,向水平方向移动再添加贝塞尔曲线,使其抛物线更加好看点
.Ball {
position: absolute;
top: 0px;
left: 0px;
z-index: 2;
transition: all 1s cubic-bezier(0.49, -0.29, 0.75, 0.41);
.inner {
position: absolute;
width: 60rpx;
height: 60rpx;
transition: all 1s linear;
}
}
在父组件只需要点击时获取到点击位置和图片信息初始位置传给我们的购物车动画组件即可
<cu-addCard :inDomStyle="ballStyle" :ballImg="ballImg" :toDomStyle="inDom"></cu-addCard>