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,很少看博客,对你有帮助别忘记点赞收藏。

相关推荐
2601_962885729 小时前
如何用 Python 扫描 A 股跳空缺口并统计缺口回补概率?
java·前端·python
西瓜太郎12349 小时前
Claude Code、Codex CLI、Gemini CLI 能否共用一枚 Key?先看协议选择矩阵
前端·api 网关·claude code·gemini cli·codex cli
多加点辣也没关系9 小时前
JavaScript|第31章:表单与控件
开发语言·javascript·ecmascript
陈随易11 小时前
在Finch用了62亿词元,我认为这是新一代Agent工具之神
前端·人工智能·后端
水域安全老周11 小时前
水趣钓鱼救生衣专利拆解:两级锁紧如何解决落水人衣分离
java·前端·网络
计算机魔术师12 小时前
Anthropic CEO突然喊踩刹车,OpenAI罕见力挺:AI这辆车不能只踩油门了
前端
wing9812 小时前
从codex转战workbuddy使用一周的感受
前端·人工智能·后端
Highcharts.js12 小时前
常见报错排雷指南2:导出失败的官方解法
javascript·react.js·ecmascript·highcharts·可视化图表·导出模块失败·导出服务
EatFan12 小时前
Java接入支付宝 JSAPI 支付保姆教程(二):流程讲解与前后端代码讲解
前端·spring boot·后端·微信小程序·小程序·uni-app
梦想平凡13 小时前
百游棋牌源代码开发搭建教程(五):房间创建、座位分配与请求幂等实现
前端·javascript·数据库·源代码管理