先看效果
具体教程
1、在component文件夹下新增一个组件叫cartfly.vue
<template>2、在需要使用购物车动画的页面中
<view class="relative">
<view class="ball" v-for="(d,i) in balls" :key="i" :style=" d.inited ? 'transition: transform .5s ease-in; transform: translate3d(0, ' + offsetY + 'px,0); top: ' + ballY + 'px;' : '' ">
<view class="inner arbg" :style="d.inited ? 'transition: transform .5s linear; transform: translate3d( ' + offsetX + 'px,0,0); left: ' + ballX + 'px; opacity: 1;' : '' "></view>
</view>
</view>
</template>
<script>
export default {
props:{
cartBasketRect:Object,// 购物车篮的rect信息
},
data() {
return {
offsetX: 0,
offsetY: 0,
ballX: 0,
ballY: 0,
balls: {},
//避免抖动
lastEvent:'',
lastId:''
}
},
created() {
let balls = [];
for (let i = 0; i < 5; i++) {
balls.push({ inited: false });
}
this.balls = balls
},
methods:{
getBalls() {
return balls;
},
addToCart (e,id) {
if(!id){
this.lastId = ''
return
}
const self = this
if(this.lastId == id){
e = this.lastEvent
}else{
this.lastId = id
this.lastEvent = e
}
let ballX = e.touches[0].clientX - 10
let ballY = e.touches[0].clientY - 9;
this.offsetX = -Math.abs(this.cartBasketRect.left - ballX + 10)
this.offsetY = Math.abs(this.cartBasketRect.top - ballY +(this.cartBasketRect.height/1.5))
this.ballX = ballX
this.ballY = ballY
for (let i = 0; i < 5; i++) {
if (!this.balls[i].inited) {
this.balls[i].inited = true
setTimeout(() => {
self.balls[i].inited= false
}, 500);
break;
}
}
}
}
}
</script>
<style scoped>
.ball {
position: fixed;
z-index:8;
}
.ball .inner {
background: #ff9900;
width: 30rpx;
height: 30rpx;
position: fixed;
border-radius: 50%;
opacity: 0;
}
</style>
<template>3、完整的项目源代码请在这里下载下载地址
<view class="content">
<view class="list">
<view class="item flex" v-for="(d,i) in shops" :key="i">
<view class="il flexs">
<image :src="d.img" mode="widthFix"></image>
<view class="">
<view class="bold name">{{d.name}}</view>
<view class="price">¥{{d.price}}</view>
</view>
</view>
<!-- 添加购车车按钮上新增一个tap事件开始动画位置 -->
<view class="add flexc bold" @tap="add($event,d.id)">+</view>
</view>
</view>
<!-- 购物车的图标,就是动画的最后位置 -->
<view class="cart">
<image id="cart" src="../../static/cart.png" mode="widthFix"></image>
</view>
<!-- 这里通过cartfly中的cartbasketRect获取上面购物车图标的位置及大小 -->
<cartfly ref="inCart" :cartBasketRect="cartBasketRect"></cartfly>
</view>
</template>
<script>
// 加入购物车动画组件
import cartfly from '@/components/cartfly.vue'
export default {
components:{
cartfly
},
data() {
return {
title: 'Hello',
//购物车位置数据
cartBasketRect:{},
//商品数据
shops:[
{id:1,img:'//repo.bfw.wiki/bfwrepo/icon/5e83debf255e9.png',name:'西红柿',price:'666'},
{id:2,img:'//repo.bfw.wiki/bfwrepo/icon/5e83debf255e9.png',name:'土豆',price:'5'},
{id:3,img:'//repo.bfw.wiki/bfwrepo/icon/5e83debf255e9.png',name:'番茄',price:'5.5'},
]
}
},
methods: {
//e 是位置等参数 id是为了重复使用点击位置点 需要保证id不重复 一般商品id不可能重复吧 (#^.^#)
add(e,id){
this.$refs.inCart.addToCart(e,id);
}
},
onPageScroll() {
//调用是因为 重复使用了点击动画位置 保证不抖动。 不传参调用即清空点击点
this.$refs.inCart.addToCart();
},
onReady() {
const self = this
let q = uni.createSelectorQuery()
//获取购物车位置
setTimeout(function(){
q.select('#cart').boundingClientRect(data => {
self.cartBasketRect = data
}).exec();
},100)
}
}
</script>
<style>
.list{
padding-top: 50rpx;
}
.price{
font-size: 30rpx;
color: red;
}
.name{
margin-bottom: 70rpx;
}
.flexs{
display: flex;
align-items: flex-start;
}
.flexc{
display: flex;
align-content: center;
justify-content: center;
}
.add{
background: #ff9900;
width: 50rpx;
height: 50rpx;
border-radius: 45%;
position: absolute;
right: 0;
transition: all .13s;
}
.add:active{
transform: scale(1.2);
}
.flex{
display: flex;
align-content: center;
}
.il{
}
.il image{
width: 160rpx;
border-radius: 16rpx;
margin-right: 20rpx;
}
.item{
width: 90%;
margin: 50rpx auto;
position: relative;
}
.flex{
display: flex;
align-items: center;
}
.bold{
font-weight: bold;
font-size: 30rpx;
}
.cart{
width: 96%;
position: fixed;
bottom: 20px;
height: 45px;
background: #1b1919;
margin: auto;
border-radius: 20px;
left: 2%;
}
.cart image{
width: 160rpx;
position: absolute;
bottom: 0;
left: 5%;
}
</style>
网友回复