小程序-貝塞爾曲線 加入購物車動畫

開篇

做爲一款2C下單小程序,產品老總說要搞一個加入購物車的動畫,第一習慣是網上找解決方案:貝塞爾算法+setInterval=>setData。html

正文

小坑

上線一段時間就出現了加入購物車總價計算負數狀況,以及計算不許,嗯。包括動畫頻繁setData期間丟失關鍵動做setData,以及添加劇復商品等bug。算法

來自小程序官方動畫支持

WXS響應事件的基礎庫要求有些高,直接放棄了。小程序

網絡社區

貝塞爾曲線算法 + setInterval=>setDataapi

function bezier(points, part) {
  let sx = points[0]['x'];
  let sy = points[0]['y'];
  let cx = points[1]['x'];
  let cy = points[1]['y'];
  let ex = points[2]['x'];
  let ey = points[2]['y'];
  var bezier_points = [];
  // 起始點到控制點的x和y每次的增量
  var changeX1 = (cx - sx) / part;
  var changeY1 = (cy - sy) / part;
  // 控制點到結束點的x和y每次的增量
  var changeX2 = (ex - cx) / part;
  var changeY2 = (ey - cy) / part;
  //循環計算
  for (var i = 0; i <= part; i++) {
    // 計算兩個動點的座標
    var qx1 = sx + changeX1 * i;
    var qy1 = sy + changeY1 * i;
    var qx2 = cx + changeX2 * i;
    var qy2 = cy + changeY2 * i;
    // 計算獲得此時的一個貝塞爾曲線上的點
    var lastX = qx1 + ((qx2 - qx1) * i) / part;
    var lastY = qy1 + ((qy2 - qy1) * i) / part;
    // 保存點座標
    var point = {};
    point['x'] = lastX;
    point['y'] = lastY;
    bezier_points.push(point);
  }
  //console.log(bezier_points)
  return {
    bezier_points
  };
}

複製代碼

而後 setInterval (坑)網絡

優化方案

綜合貝塞爾曲線和wx.createAnimationide

method:{
   touchOnGoods(e) {
      // 若是good_box正在運動
      if (!this.data.hide_good_box) return;
      const { touches } = e;
      const topPoint = {};

      this.finger = {
        x: touches[0].clientX,
        y: touches[0].clientY
      };

      topPoint['y'] =
        this.finger['y'] < this.busPos['y']
          ? this.finger['y'] - 150
          : this.busPos['y'] - 150;

      topPoint['x'] =
        this.finger['x'] > this.busPos['x']
          ? (this.finger['x'] - this.busPos['x']) / 2 + this.busPos['x']
          : (this.busPos['x'] - this.finger['x']) / 2 + this.finger['x'];

      const result = bezier([this.finger, topPoint, this.busPos], 25);
      this.startAnimation(result);
    },
    startAnimation(linePos) {
      const { bezier_points } = linePos;
      const len = bezier_points.length - 1;
      const first = bezier_points.shift();
    //防止動畫不生效
    //同一個按鈕動畫,動畫開始前先歸位元素位置
      this.setData(
        {
          hide_good_box: false,
          initLeft:first.x,
          initTop:first.y,
          animationData: this.animation.export()
        },
        () => {
          bezier_points.forEach((i, idx) => {
            this.animation
              .left(i.x)
              .top(i.y)
              .rotate(50)
              .step({ duration: 25 });
          });
          this.setData({
            animationData: this.animation.export()
          });
        }
      );
      //有個bug,就是連續點擊,動畫不出來
      setTimeout(() => {
        this.setData({ hide_good_box: true });
      }, len * 20 + 100);
    }
  },
  ready() {
    this.busPos = { x: 50, y: 601 };
    //調用同步接口 略有問題
    this.busPos.y = util.getSysInfo().windowHeight - 66;

    this.animation = wx.createAnimation({
      timingFunction: 'ease-in',
      delay: 0,
      duration: 1000
    });
  }
//有點懶,直接貼源代碼了
複製代碼
<view class="good_box" hidden="{{hide_good_box}}" style="left:{{initLeft}}px;top:{{initTop}}px" animation="{{animationData}}"></view>
<view bindtap="touchOnGoods">
  <slot></slot>
</view>
複製代碼

結尾

其實好的解決方案,應該是排除低端手機,尤爲是安卓機子來啓用動畫。 暫時沒有其餘好的idea了,由於不多搞動畫,缺少經驗。有同行仁兄多多指交。優化

相關文章
相關標籤/搜索