1. 程式人生 > >vue 2.0 購物車小球拋物線

vue 2.0 購物車小球拋物線

備註:此專案模仿 餓了嗎。我用的是最新的Vue, 視訊上的一些寫法已經被廢棄了。

佈局程式碼


<div class="ball-container">
  <transition name="drop"
              v-for="ball in balls"
              @before-enter="beforeDrop"
              @enter="dropping"
              @after-enter="afterDrop">
    <div v-show="ball.show" class="ball" v-bind:css="false">
      <div class="inner inner-hook" ></div>
    </div>
  </transition>
</div>

css程式碼(使用stylus寫法)


.ball-container
  .ball
    position fixed
    left 32px
    bottom 22px
    z-index 200
    transition all 0.4s cubic-bezier(0.49,-0.29,0.75,0.41)
    .inner
      width 16px
      height 16px
      border-radius 50%
      background-color rgb(0,160,220)
      transition all 0.4s linear

js程式碼


data() {
    return {
      balls : [
        {
          show: false
        },
        {
          show: false
        },
        {
          show: false
        },
        {
          show: false
        },
        {
          show: false
        }
      ],
      dropBalls: []
    };
},     
methods: {
    drop(el) {
      for(let i = 0; i < this.balls.length; i++) {
        let ball = this.balls[i];
        if(!ball.show) {
          ball.show = true;
          ball.el = el;
          this.dropBalls.push(ball);
          return ;
        }
      }
    }
    beforeDrop(el) {
      let count = this.balls.length;
      while (count--) {
        let ball = this.balls[count];
        if(ball.show) {
          let rect = ball.el.getBoundingClientRect();
          let x = rect.left - 32;
          let y = -(window.innerHeight - rect.top - 22);
          el.style.webkitTransform = `translate3d(0,${y}px,0)`;
          el.style.transform =  `translate3d(0,${y}px,0)`;
          let inner = el.getElementsByClassName('inner-hook')[0];
          inner.style.webkitTransform =  `translate3d(${x}px,0,0)`;
          inner.style.transform = `translate3d(${x}px,0,0)`;
        }
      }
    },
    dropping(el) {
      /* eslint-disable no-unused-vars */
      let rf = el.offsetHeight;
      this.$nextTick(() => {
        el.style.webkitTransform = 'translate3d(0,0,0)';
        el.style.transform =  'translate3d(0,0,0)';
        let inner = el.getElementsByClassName('inner-hook')[0];
        inner.style.webkitTransform = 'translate3d(0,0,0)';
        inner.style.transform = 'translate3d(0,0,0)';
      });
    },
    afterDrop(el){
      let ball = this.dropBalls.shift();
      if(ball) {
        ball.show = false;
        el.style.display = 'none';
      }
    }
}

getBoundingClientRect()。方法請閱讀這篇文章
https://www.cnblogs.com/limei...

說明:
goods 是一個元件,裡面包含menu(div) , foods(div), shopcart(購物車元件)。其中foods 包含cartcontrol(即小球元件)

元件之間的通訊:
說明:選單和商品

第1個問題:小球,需要獲取所點選的商品的數量。
利用Vue的props,將foods值傳遞給cartcontrol。但是這樣有個問題。即子元件更新,無法同步回父元件。且,在子元件中,對food註冊了一個count屬性,此屬性也無法同步回父元件(goods)。
解決方法:
匯入全域性的Vue。
利用Vue.set(target,key,value); 對 target註冊count;

第2個問題:小球點選,將所點選過的商品數目傳遞給 shopcart。
在goods的 computed:{} 定義一個方法,將該方法以props的方式,傳遞給shopcart。
因為,shopcart,對傳遞過去的資料僅資料運算(不會改變)。因此不用同步會父元件。

第3個問題:購物車小球做拋物線運動。
對於購物車小球做拋物線運動。首先,落點都在購物車,小球則是隨機的。要做拋物線運動,就要獲取,所點選的 + 號的x,y位置。其次,拋物線運動,只有在enter--> enter-to這段期間有,在leave--> leave-to 期間是沒有的,因此,需要用Vue提供的鉤子函式。

獲取 + 號x,y 位置:
小球(cartcontrol)是子元件。需要把資料傳遞給 goods(父元件)。可以使用Vuex,或者直接使用事件匯流排。對於餓了嗎demo。直接使用事件匯流排。
建立一個 空的Vue。在 cartcontrol 中 ,通過 Bus.$emit(key, ... arg); 註冊一個監聽,然後再父元件 通過Bus.$on(key, function(... arg));監聽此方法。將所操作的 dom 物件傳遞過去即可

Vue提供的鉤子
這裡要說明一點,Vue在他的官網,對於只有過度的js,done是必須的,當我加上done的時候,after-enter方法無法被執行。
還有1個問題,Vue官網推薦,只有過度效果,在做過度動畫的元素上加上v-bind:class='false'。之前沒加,出現了,小球只能在第1次點選的地方做過度效果。

原文地址:https://segmentfault.com/a/1190000013081705