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

相关推荐
新中地GIS开发老师15 小时前
WebGIS开发学生作品|低空航天管理与航线规划系统
前端·javascript·webgis·三维gis开发
用户0595401744615 小时前
大模型对话记忆持久化踩坑实录:用 Playwright 自动化测了 300 次,终于揪出会话丢失的真凶
前端·css
丙氨酸長鏈15 小时前
Web前端入门第 问:JavaScript 一个简单的 IndexedDB 数据库入门示例
前端·javascript·数据库
kyriewen16 小时前
面试官让我手写虚拟列表——AI生成的版本,快速滚动几下就白屏了
前端·javascript·面试
IT_陈寒16 小时前
Vite热更新失效?你可能漏了这个配置
前端·人工智能·后端
梅孔立17 小时前
两种免费的翻译API调用方式详解 - Edge官方API与个人缓存服务
前端·缓存·edge
Revolution6117 小时前
React 组件重新渲染时,到底重新执行了什么
前端·react.js·面试
林焱_RPAAI17 小时前
影刀RPA技术深度:CSS选择器高级实战指南——伪类属性选择器与性能对比完全解析
vue.js·react.js
用户21816970493018 小时前
Flutter(四)Dart语法 空安全 运算符 流程控制
前端
许彰午18 小时前
政务督办的分合模式:主办协办的并发审批
前端·javascript·政务