vue3加入购物车特效

1.新建个购物车动画组件

<script setup lang="ts">
import { ref, defineExpose, reactive } from "vue";
// 背景色
const PrimaryColor = ref("#71ce58");
const hide_good_box = ref(true);

// 默认掉落坐标
const busPosDefault = {
  x: window.innerWidth - 140,
  y: window.innerHeight + 100,
};
const bus_x = 0;
const bus_y = 0;
//坐标列队动画坐标
const linePosArr = ref([]);
//点击商品触发的事件
const touchOnGoods = (e, busPos) => {
  console.log(busPos, "坐标");
  console.log(e, "进入动画");
  if (busPos) {
    //是否自定义掉落坐标
    busPosDefault.value = busPos;
  }
  // 如果good_box正在运动
  // if (!this.hide_good_box) return;
  var cell = {
    finger: {}, //点击的位置坐标
    flag: false, //false:倒序,true:正序
    hide_good_box: false, //是否显示
    linePos: {}, //运动轨迹
    bus_x: 0, //运动的x坐标
    bus_y: 0, //运动的Y坐标
    timer: "", //定时器
  };
  console.log(cell);
  // debugger;
  var topPoint = {};
  cell.finger["x"] = e.clientX; //点击的位置
  cell.finger["y"] = e.clientY;
  if (cell.finger["y"] < busPosDefault["y"]) {
    topPoint["y"] = cell.finger["y"] - 150;
  } else {
    topPoint["y"] = busPosDefault["y"] - 150;
  }
  topPoint["x"] = Math.abs(cell.finger["x"] - busPosDefault["x"]) / 2;
  console.log("坐标对比", cell.finger["x"] > busPosDefault["x"]);

  if (cell.finger["x"] > busPosDefault["x"]) {
    topPoint["x"] = (cell.finger["x"] - busPosDefault["x"]) / 2 + busPosDefault["x"];
    cell.linePos = bezier([busPosDefault, topPoint, cell.finger], 30);
    cell.flag = false;
  } else {
    //
    topPoint["x"] = (busPosDefault["x"] - cell.finger["x"]) / 2 + cell.finger["x"];
    cell.linePos = bezier([cell.finger, topPoint, busPosDefault], 30);
    cell.flag = true;
  }
  console.log("动画", cell);

  linePosArr.value.push(cell);
  console.log("动画队列", linePosArr);

  startAnimation(cell, linePosArr.value.length - 1);
};
//开始动画
const startAnimation = (item, i) => {
  // uni.vibrateShort(); //震动方法
  console.log("bezier_points", item.linePos);
  console.log(linePosArr.value, i);

  var bezier_points = item.linePos["bezier_points"];
  let index = bezier_points.length;
  // console.log(bezier_points, 'bezier_points')
  (item.hide_good_box = false), (item.bus_x = item.finger["x"]);
  item.bus_y = item.finger["y"];
  if (!item.flag) {
    index = bezier_points.length;
    item.timer = setInterval(function () {
      index--;
      linePosArr.value[i].bus_x = bezier_points[index]["x"];
      linePosArr.value[i].bus_y = bezier_points[index]["y"];
      if (index <= 1) {
        clearInterval(item.timer);
        item.hide_good_box = true;
        linePosArr.value.splice(0, 1); //动画完成,删除第一个队列
      }
    }, 30);
  } else {
    index = 0;
    item.timer = setInterval(function () {
      index++;
      linePosArr.value[i].bus_x = bezier_points[index]["x"];
      linePosArr.value[i].bus_y = bezier_points[index]["y"];
      if (index >= 28) {
        clearInterval(item.timer);
        item.hide_good_box = true;
        linePosArr.value.splice(0, 1); //动画完成,删除第一个队列
      }
    }, 30);
  }
};
const bezier = (points, times) => {
  // 0、以3个控制点为例,点A,B,C,AB上设置点D,BC上设置点E,DE连线上设置点F,则最终的贝塞尔曲线是点F的坐标轨迹。
  // 1、计算相邻控制点间距。
  // 2、根据完成时间,计算每次执行时D在AB方向上移动的距离,E在BC方向上移动的距离。
  // 3、时间每递增100ms,则D,E在指定方向上发生位移, F在DE上的位移则可通过AD/AB = DF/DE得出。
  // 4、根据DE的正余弦值和DE的值计算出F的坐标。
  // 邻控制AB点间距
  var bezier_points = [];
  var points_D = [];
  var points_E = [];
  const DIST_AB = Math.sqrt(
    Math.pow(points[1]["x"] - points[0]["x"], 2) +
      Math.pow(points[1]["y"] - points[0]["y"], 2)
  );
  // 邻控制BC点间距
  const DIST_BC = Math.sqrt(
    Math.pow(points[2]["x"] - points[1]["x"], 2) +
      Math.pow(points[2]["y"] - points[1]["y"], 2)
  );
  // D每次在AB方向上移动的距离
  const EACH_MOVE_AD = DIST_AB / times;
  // E每次在BC方向上移动的距离
  const EACH_MOVE_BE = DIST_BC / times;
  // 点AB的正切
  const TAN_AB = (points[1]["y"] - points[0]["y"]) / (points[1]["x"] - points[0]["x"]);
  // 点BC的正切
  const TAN_BC = (points[2]["y"] - points[1]["y"]) / (points[2]["x"] - points[1]["x"]);
  // 点AB的弧度值
  const RADIUS_AB = Math.atan(TAN_AB);
  // 点BC的弧度值
  const RADIUS_BC = Math.atan(TAN_BC);
  // 每次执行
  for (var i = 1; i <= times; i++) {
    // AD的距离
    var dist_AD = EACH_MOVE_AD * i;
    // BE的距离
    var dist_BE = EACH_MOVE_BE * i;
    // D点的坐标
    var point_D = {};
    point_D["x"] = dist_AD * Math.cos(RADIUS_AB) + points[0]["x"];
    point_D["y"] = dist_AD * Math.sin(RADIUS_AB) + points[0]["y"];
    points_D.push(point_D);
    // E点的坐标
    var point_E = {};
    point_E["x"] = dist_BE * Math.cos(RADIUS_BC) + points[1]["x"];
    point_E["y"] = dist_BE * Math.sin(RADIUS_BC) + points[1]["y"];
    points_E.push(point_E);
    // 此时线段DE的正切值
    var tan_DE = (point_E["y"] - point_D["y"]) / (point_E["x"] - point_D["x"]);
    // tan_DE的弧度值
    var radius_DE = Math.atan(tan_DE);
    // 地市DE的间距
    var dist_DE = Math.sqrt(
      Math.pow(point_E["x"] - point_D["x"], 2) + Math.pow(point_E["y"] - point_D["y"], 2)
    );
    // 此时DF的距离
    var dist_DF = (dist_AD / DIST_AB) * dist_DE;
    // 此时DF点的坐标
    var point_F = {};
    point_F["x"] = dist_DF * Math.cos(radius_DE) + point_D["x"];
    point_F["y"] = dist_DF * Math.sin(radius_DE) + point_D["y"];
    bezier_points.push(point_F);
  }
  return {
    bezier_points: bezier_points,
  };
};
defineExpose({
  touchOnGoods,
});
</script>

<template>
  <div>
    <block v-for="(item, index) in linePosArr" :key="index">
      <view
        class="good_box"
        :style="[
          { left: item.bus_x + 'px', top: item.bus_y + 'px', background: PrimaryColor },
        ]"
      ></view>
    </block>
  </div>
</template>

<style lang="scss" scoped>
.good_box {
  width: 30px;
  height: 30px;
  position: fixed;
  border-radius: 50%;
  overflow: hidden;
  left: 50%;
  top: 50%;
  z-index: +99;
  border: 1px solid #fff;
  background: red;
}
</style>

2. 在页面中引入组件,创建点击事件

    <!-- 加入购物车动画组件 -->
    <cus-addCar ref="cartAnimation"></cus-addCar>
    <div
              class="selectedBox"
              style="background: #71ce58"
              @click.stop="selectItem($event, item)"
              v-if="item.flg == 0"
      >
      选择</div>

3.填写点击事件触发购物车加入购物车特效,


const selectItem = (event: any, item) => {
//props,需要加入购物车的位置
 cartAnimation.value.touchOnGoods(event, { carX,carY});
};

4. 随着窗口的变化,购物车的位置也会相应改变,所以需要监听实时位置

const carX = ref();
const carY = ref();
onMounted(() => {
  const bottomCar = document.querySelector(".car_btn");
  window.onresize = () => {
    return (() => {
     //购物车位置
      carY.value = bottomCar.getBoundingClientRect().y;
      carX.value = bottomCar.getBoundingClientRect().x;
    })();
  };
});
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值