重点:抛物线:父子盒子,父盒子x轴水平匀速运动,子盒子y轴贝塞尔曲线运动
html
<template>
<div class="cart">
<div v-for="(item,idx) in goodList" :key="idx" class="item">
<img
class="item-image"
src="https://img0.baidu.com/it/u=2020518972,2077284106&fm=253&app=120&size=w931&n=0&f=JPEG&fmt=auto?sec=1702400400&t=2b15baf23601a38e228295ef16ef03c1"
/>
<div class="item-content">
<div class="item-content-title">{{ item.name }}d大家为吉德科娃监</div>
<div class="item-content-btm">
<div class="item-content-btm-quan">{{ item.quantity }}</div>
<div class="item-content-btm-add" @click="handelAdd" >
+
</div>
</div>
</div>
</div>
<div class="cart-box">
<div class="cart-title" ref="cartRef">购物车</div>
</div>
</div>
</template>
js
<script setup>
import { reactive,ref } from "vue";
const goodList = reactive([{name:123,quantity:123},{name:123,quantity:123},{name:123,quantity:123},{name:123,quantity:123},])
const cartRef = ref(null)
function handelAdd(e){
const div = document.createElement('div')
div.className = 'add'
div.innerHTML = '<div class="add-icon">+</div>'
const target = e.target
const btnRect = target.getBoundingClientRect()
console.log(btnRect,e)
const left = btnRect.left + btnRect.width / 2 - 10
const top = btnRect.top - 10
div.style.setProperty('--left',left+'px')
div.style.setProperty('--top',top+'px')
const cartRect = cartRef.value.getBoundingClientRect()
const x = cartRect.left + cartRect.width / 2 - 10 - left
const y = cartRect.top - 10 - top
div.style.setProperty('--x',x+'px')
div.style.setProperty('--y',y+'px')
div.addEventListener('animationend',()=>{
div.remove()
})
document.body.appendChild(div)
}
</script>
css
<style lang="scss" >
.cart{
width: 100%;
background: #f5f5f5;
height: 100vh;
padding: 16px;
box-sizing: border-box;
}
.item{
width: 100%;
margin-bottom: 16px;
background: #fff;
border-radius: 10px;
padding: 8px;
box-sizing: border-box;
display: flex;
&-image {
width: 60px;
height: 60px;border-radius: 12px;
margin-right: 8px;
}
&-content{
flex: 1;
display: flex;
flex-direction: column;
justify-content: space-between;
&-title{
font-size: 14px;
color: #333;
margin-bottom: 4px;
}
&-btm{
display: flex;
justify-content: space-between;
&-quan{
font-size: 14px;
color: #333;
}
&-add{
margin-right: 10px;
font-size: 19px;
border: #ccc 1px solid;
color: #ccc;
border-radius: 50%;
width: 20px;
height: 20px;
text-align: center;
line-height: 16px;
}
}
}
}
.cart-box{
width: 100%;
position: fixed;
left: 0;right: 0;
bottom: 0;
background: #fff;
}
.cart-title{
background: lightcoral;
color: #333;
font-size: 18px;
font-weight: 600;
padding: 20px;
width: 60px;
text-align: center;
}
.add{
width: 30px;
height: 30px;
border-radius: 50%;
position: fixed;
left: var(--left);
top:var(--top);
// border: 2px solid #333;
}
.add-icon{
color: #fff;
width: 100%;
height: 100%;
text-align: center;
line-height: 28px;
background: orange;
border-radius: 100%;
}
@keyframes moveY {
to{
transform: translateY(var(--y));
}
}
.add{
--duration:0.8s;
animation: moveX var(--duration) linear;
}
@keyframes moveX {
to{
transform: translateX(var(--x));
}
}
.add-icon{
animation: moveY var(--duration) cubic-bezier(0.5,-0.5,1,1);
}
</style>