vue.js加入購物車小球動畫

  • 生成一個動畫小球的div,而且生成五個小球,五個是爲了生成必定數量的小球來做爲操做使用,按照小球動畫的速度,通常來講五個也能夠保證有足夠的小球數量來運行動畫css

  • 動畫的內容分別是外層和內層,外層控制動畫小球的軌道和方向,內層控制動畫小球的運行狀態html

  • 動畫使用vue的js鉤子實現vue

  • 由於小球動畫只有一個方向(只執行單方向從上到下滾落),因此只用了before-enter,enter,after-entercss3

  • 用v-show控制小球的可見性,在動畫執行期間可見,其他時候隱藏web

  • <div class="ball-container">
            <transition name="fade" v-for="ball in balls" :key="ball" @before-enter="beforeEnter" @enter="enter" @after-enter="afterEnter">
              <div class="ball" v-show="ball.show">
                <div class="inner inner-hook"></div>
              </div>
            </transition>
        </div>
    • 設置了balls數組來表明五個小球canvas

    • 設置了dropBalls數組正在運行的小球segmentfault

 

    data(){
      return {
        balls: [
          {
            show: false
          },
          {
            show:  false
          },
          {
            show:  false
          },
          {
            show:  false
          },
          {
            show:  false
          }
        ],
        dropBalls:[]
      }
    },

 

      • 只要觸發了drop事件,不止是drop事件裏面的代碼會執行,另外幾個vue的js監聽鉤子也會一塊兒按順序執行api

        • 觸發了drop事件數組

        • beforeEnter開始執行瀏覽器

        • enter開始執行

        • afterEnter開始執行

      • drop事件的觸發能夠經過點擊cartcontrol組件的添加小球按鈕addCart事件觸發使用$emit,也能夠父組件this.$refs.shopcart.drop(target);直接觸發

        • 這麼作的目的是實現,在子組件cartcontrol點擊以後,能夠將該dom傳給父組件goods而後再傳給子組件shopcart,(由於目前他們之間的通道就是這樣,shopcart子組件並無導入cartcontrol子組件,因此沒有直接通信)這樣就實現了多個組件之間的通信,從而能夠實現需求,例如這裏就是實現點擊子組件cartcontrol後添加一個動畫,將小球滑落到另一個組件shopcart

      • $emit是觸發當前實例上的事件。附加參數都會傳給監聽器回調。

methods: {
      drop(el) { 
      //觸發一次事件就會將全部小球進行遍歷
        for (let i = 0; i < this.balls.length; i++) {
          let ball = this.balls[i];
          if (!ball.show) { //將false的小球放到dropBalls
            ball.show = true;
            ball.el = el; //設置小球的el屬性爲一個dom對象
            this.dropBalls.push(ball); 
            return;
          }
        }
      },

      beforeEnter(el){ //這個方法的執行是由於這是一個vue的監聽事件
        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.display = ''; //清空display
            el.style.webkitTransform = `translate3d(0,${y}px,0)`; 
            el.style.transform = `translate3d(0,${y}px,0)`;
            //處理內層動畫
            let inner = el.getElementsByClassName('inner-hook')[0]; //使用inner-hook類來單純被js操做
            inner.style.webkitTransform = `translate3d(${x}px,0,0)`;
            inner.style.transform = `translate3d(${x}px,0,0)`;
          }
        }
      },

      enter(el, done) { //這個方法的執行是由於這是一個vue的監聽事件
        /* eslint-disable no-unused-vars */
        let rf = el.offsetHeight; //觸發重繪html
        this.$nextTick(() => { //讓動畫效果異步執行,提升性能
          el.style.webkitTransform = 'translate3d(0,0,0)';
          el.style.transform = 'translate3d(0,0,0)';
          //處理內層動畫
          let inner = el.getElementsByClassName('inner-hook')[0]; //使用inner-hook類來單純被js操做
          inner.style.webkitTransform = 'translate3d(0,0,0)';
          inner.style.transform = 'translate3d(0,0,0)';
          el.addEventListener('transitionend', done); //Vue爲了知道過渡的完成,必須設置相應的事件監聽器。
        });
      },

      afterEnter(el) { //這個方法的執行是由於這是一個vue的監聽事件
        let ball = this.dropBalls.shift(); //完成一次動畫就刪除一個dropBalls的小球
        if (ball) {
          ball.show = false;
          el.style.display = 'none'; //隱藏小球
        }
      }
    }
  • 關於transitionend

  • 關於drop方法,是實現每個ball的show屬性和el屬性處理,而且點擊一次會自動將一個小球放到dropBalls數組裏面,放到裏面就表明的是一個小球已經被開始執行動畫,可是因爲動畫是異步的,因此先主動設置.

  • 關於getBoundingClientRect(位移的計算是從左上角開始)

    • 使用getBoundingClientRect獲取到當前元素的座標,而後須要位移的left減去元素的寬獲取真正的最終位移x座標

    • 使用getBoundingClientRect獲取到當前元素的座標,而後須要當前屏幕的高度減去元素的top再減去元素自己的高度獲取到真正的最終位移y座標,而且這個是負數,由於是從左上角往下的方向

  • 關於html重繪

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

關於cubic-bezier(0.49, -0.29, 0.75, 0.41),是動畫拋物曲線(貝塞爾曲線)的配置,基於css3實現,http://cubic-bezier.com/#.17,.67,.83,.67,參考貝塞爾曲線與CSS3動畫、SVG和canvas的基情 ,至於拋物線放在外層就是爲了控制內層的元素的軌道和方向的.

 

參考自http://www.javashuo.com/article/p-ocsklkqx-dt.html

相關文章
相關標籤/搜索