vue 加入购物车抛物线动画

效果图


购物车主要是两张图,分别是盖子和篮子组成一个图,点击事件默认能获取页面点击X和Y

.vue

typescript 复制代码
<template>
  <view
    v-for="ball in balls"
    :key="ball.id"
    class="ball"
    :style="{
      '--x': `${ball.x - 30}px`,
      '--y': `${ball.y - 20}px`,
    }" />
  <view class="btn wxy-button flex-between">
    <view class="flex">
      <view class="btn-item">
        <image class="btn-item-lid" :src="imgUrl('home/lid')"
               :class="{'btn-item-lid-active': balls.length > 0}" />
        <image class="btn-item-basket" :src="imgUrl('home/basket')" />
      </view>
      <wxy-text-price :num="2.5" :digit="2" />
    </view>
    <view class="wxy-btn flex-center btn-button bg-main round">
      去结算
    </view>
  </view>
</template>

<script setup lang='ts'>
import { imgUrl } from '@/modules/tool'
import { watch, ref } from 'vue'

interface Ball {
  id: number
  x: number
  y: number
}

const props = defineProps({
  location: {
    type: Object,
    default: () => ({
      x: 0,
      y: 0,
    }),
  },
})

const balls = ref<Ball[]>([])
let ballId = 0

watch(() => props.location, (newLoc) => {
  if (newLoc.x !== 0 || newLoc.y !== 0) {
    const newBall: Ball = {
      id: ++ballId,
      x: newLoc.x,
      y: newLoc.y,
    }
    balls.value.push(newBall)

    setTimeout(() => {
      const index = balls.value.findIndex((b) => b.id === newBall.id)
      if (index > -1) {
        balls.value.splice(index, 1)
      }
    }, 800)
  }
})
</script>

<style lang='scss' scoped>
.ball {
  position: absolute;
  top: var(--y);
  left: var(--x);
  z-index: 3;
  width: 48rpx;
  height: 48rpx;
  background-color: var(--main);
  border-radius: 50%;
  animation: fly-to-cart 1s cubic-bezier(0.2, 0.8, 0.2, 1) forwards;
  pointer-events: none;
  will-change: transform;
}

@keyframes fly-to-cart {
  to{
    transform: translate(calc(30rpx - var(--x)), calc(100vh - 100rpx - var(--y))) scale(0.6);
  }
}

.btn{
  padding: 20rpx 30rpx calc(20rpx + (env(safe-area-inset-bottom) / 2));

  &-button{
    width: 280rpx;
    height: 84rpx;
    font-weight: 500;
  }

  &-item{
    --size:166rpx;
    --top:-30rpx;

    width: 110rpx;

    &-lid{
      position: absolute;
      top: var(--top);
      left: 0;
      z-index: 1;
      width: var(--size);
      height: var(--size);
      backface-visibility: hidden;
      transition: .4s ease-in-out;
      will-change: transform;
    }

    &-lid-active{
      transform: rotate(-60deg) translateY(-30rpx) translateX(20rpx);
    }

    &-basket{
      position: absolute;
      top: var(--top);
      left: 0;
      width: var(--size);
      height: var(--size);
    }
  }
}
</style>

遇到问题可以看我主页加我Q,很少看博客,对你有帮助别忘记点赞收藏。

相关推荐
计算机学姐1 小时前
基于微信小程序的图书馆座位预约系统【uniapp+springboot+vue】
vue.js·spring boot·微信小程序·小程序·java-ee·uni-app·intellij-idea
切糕师学AI2 小时前
为什么你的 SPA 网址必须包含 `#`?—— 前端路由 Hash 模式深度解析
前端·spa 网址·hash路由
冴羽2 小时前
超越Vibe Coding —— AI 辅助编程进阶指南
前端·javascript·ai编程
流氓也是种气质 _Cookie2 小时前
Chrome Performance常见名词解释(FP, FCP, LCP, DCL, FMP, TTI, TBT, FID, CLS)
开发语言·javascript·ecmascript
MXN_小南学前端2 小时前
自制和整理常用前端 AI Skills分享,从需求到页面(附github地址)
前端·ai编程
yuki_uix2 小时前
双 RAF + MutationObserver:微前端跳转后的滚动复原完整方案
前端
暗不需求2 小时前
一文吃透 React Context:跨层级通信的利器
前端·javascript·react.js
Wect2 小时前
前端工程化 Mock 数据原理与实践
前端·api·前端工程化
小宇的天下2 小时前
Calibre DESIGNrev 单元(Cell)操作核心指南
java·前端·javascript