微信小程序 类似点餐系统功能

本文详细介绍了一个基于微信小程序的商品购物动画实现方案,通过自定义动画效果,增强了用户在浏览商品时的交互体验。文章深入解析了如何利用贝塞尔曲线计算商品到购物车的路径,并实现了商品图片跟随手指触点移动并最终进入购物车的动画效果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

<!--index.wxml-->
<view class="container">
  <scroll-view>
    <view bindtap="touchOnGoods" wx:key="keys" class="goods" hover-class="goods_hover" wx:for="{{goods_list}}">
      <image src="https://dss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=1101358545,1075987855&fm=26&gp=0.jpg" mode="widthFix"></image>
    </view>
  </scroll-view>

  <view class="{{needAni ? 'bus scale': 'bus'}}">
    <image src="../../images/bus.png"></image>
    <view class="count" hidden="{{hideCount}}">{{count}}</view>
  </view>

  <view class="good_box" hidden="{{hide_good_box}}"  style="left: {{bus_x}}px; top: {{bus_y}}px;">
    <image src="https://dss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=1101358545,1075987855&fm=26&gp=0.jpg"></image>
  </view>
</view>

/**index.wxss**/

swiper {
  height: 168px;
}

.slide-image {
  width: 100%;
  height: 168px;
}

scroll-view {
  margin-top: 5px;
}

.goods {
  width: 48%;
  margin: 1%;
  float: left;
  background: #fff;
}

.goods_hover {
  transform: scale(0.98);
}

.goods image {
  width: 100%;
}

.bus {
  width: 48px;
  height: 48px;
  position: fixed;
  left: 80%;
  top: 80%;
  background: rgba(120, 188, 255, 0.6);
  border: 1px solid rgba(0, 116, 255, 0.61);
  border-radius: 50%;
}

.bus image {
  width: 32px;
  height: 32px;
  position: absolute;
  left: 50%;
  top: 50%;
  margin: -16px;
}

.count {
  display: block;
  height: 20px;
  line-height: 20px;
  font-size: 12px;
  background: #ff4611;
  padding: 0 6px;
  border-radius: 10px;
  color: #fff;
  position: absolute;
  left: 34px;
  top: 0;
}

.scale {
  background: rgba(120, 188, 255, 0.3);
  border: 1px solid rgba(0, 116, 255, 0.4);
}

.scale image {
  transform: scale(1.2);
}

.good_box {
  width: 40px;
  height: 40px;
  position: fixed;
  border-radius: 50%;
  overflow: hidden;
  left: 50%;
  top: 50%;
  z-index: +99;
  border: 1px solid rgba(0, 116, 255, 0.61);
  background: rgba(120, 188, 255, 0.2);
}
.good_box image {
  display: block;
  width: 100%;
  height: 100%;
}

//index.js
//获取应用实例
var app = getApp()
Page({
  data: {
    imgUrls: [
      '../../images/banner1.jpg',
      '../../images/banner2.jpg',
      '../../images/banner3.jpg'
    ],
    indicatorDots: false,
    autoplay: false,
    interval: 5000,
    duration: 500,
    goods_list: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
    hideCount: true,
    count: 0,
    needAni: false,
    hide_good_box: true
  },
  onLoad: function() {
    var that = this;
    this.busPos = {};
    this.busPos['x'] = app.globalData.ww * 0.8;
    this.busPos['y'] = app.globalData.hh * 0.8;
  },
  busAnimation: function() {
    that.setData({
      needAni: true
    });
    setTimeout(function() {
      that.setData({
        needAni: false
      });
    }, 500);
  },
  touchOnGoods: function(e) {
     // 如果good_box正在运动
    if (!this.data.hide_good_box) return;
    this.finger = {};
    var topPoint = {};
    this.finger['x'] = e.touches["0"].clientX;
    this.finger['y'] = e.touches["0"].clientY;
    if (this.finger['y'] < this.busPos['y']) {
      topPoint['y'] = this.finger['y'] - 150;
    } else {
      topPoint['y'] = this.busPos['y'] - 150;
    }
    topPoint['x'] = Math.abs(this.finger['x'] - this.busPos['x']) / 2 + this.finger['x'];
    this.linePos = app.bezier([this.finger, topPoint, this.busPos], 30);
    this.startAnimation();
  },
  startAnimation: function() {
    var index = 0,
      that = this,
      bezier_points = that.linePos['bezier_points'];
    this.setData({
      hide_good_box: false,
      bus_x: that.finger['x'],
      bus_y: that.finger['y']
    })
    this.timer = setInterval(function() {
      index++;
      that.setData({
        bus_x: bezier_points[index]['x'],
        bus_y: bezier_points[index]['y']
      })
      if (index >= 28) {
        clearInterval(that.timer);
        that.setData({
          hide_good_box: true,
          hideCount: false,
          count: that.data.count += 1
        })
      }
    }, 33);
  }
})

app.js里面的内容

//app.js
App({
  onLaunch: function () {
    this.screenSize();
  },

  screenSize: function () {
    var that = this;
    wx.getSystemInfo({
      success: function (res) {
        var ww = res.windowWidth;
        var hh = res.windowHeight;
        that.globalData.ww = ww;
        that.globalData.hh = hh;
      }
    })
  },

  bezier: function (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
    };
  },

  globalData: {
    userInfo: null
  }
})

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值