Vue.js動畫和過渡

vue中的過渡與動畫

過濾

把需要添加動畫效果的DIV放到transition標籤

之後就會發生以下3個步驟

  1. 自動嗅探目標元素是否應用了 CSS 過渡或動畫,如果是,在恰當的時機添加/刪除 CSS 類名(等下要寫的6個類名)。

  2. 如果過渡組件提供了 JavaScript 鉤子函數,這些鉤子函數將在恰當的時機被調用。

  3. 如果沒有找到 JavaScript 鉤子並且也沒有檢測到 CSS 過渡/動畫,DOM 操作 (插入/刪除) 在下一幀中立即執行。(注意:此指瀏覽器逐幀動畫機制,和 Vue 的 nextTick 概念不同)

類名

v-enter:定義進入過渡的開始狀態。在元素被插入之前生效,在元素被插入之後的下一幀移除。

v-enter-active:定義進入過渡生效時的狀態。在整個進入過渡的階段中應用,在元素被插入之前生效,在過渡/動畫完成之後移除。這個類可以被用來定義進入過渡的過程時間,延遲和曲線函數。

v-enter-to2.1.8版及以上 定義進入過渡的結束狀態。在元素被插入之後下一幀生效 (與此同時 v-enter 被移除),在過渡/動畫完成之後移除。

v-leave: 定義離開過渡的開始狀態。在離開過渡被觸發時立刻生效,下一幀被移除。

v-leave-active:定義離開過渡生效時的狀態。在整個離開過渡的階段中應用,在離開過渡被觸發時立刻生效,在過渡/動畫完成之後移除。這個類可以被用來定義離開過渡的過程時間,延遲和曲線函數。

v-leave-to2.1.8版及以上 定義離開過渡的結束狀態。在離開過渡被觸發之後下一幀生效 (與此同時 v-leave 被刪除),在過渡/動畫完成之後移除。

插入

其實是看完了文檔我也是一臉懵逼,看到這裏其實有很多問題就出來了,下面我們一一列舉一一解答

  1. 什麼是定義進入/離開過渡
  2. 什麼是在元素被插入之前,這個插入是插入到什麼地方
  3. 當我們自身元素的css樣式和v-enter,v-enter-to,v-leave,v-leave-to會出現重複嗎?,是會覆蓋還是不會覆蓋,而且覆蓋是誰覆蓋誰,是自身的樣式權重高呢,還是v-enter...呢?
  4. v-if和v-show的區別

1.什麼是定義進入/離開過渡

進入過渡:元素顯示的過程

離開過渡:元素離開的過程

以前我理解這個就是有一個地方無法理解,明明不管元素是顯示還是隱藏他們都是一個過渡過程,那麼其實他們(顯示過程或離開過程)都是代表的進入過渡,對吧,我以前一直以爲是文檔表達的不清楚,但是後來我發現我自己太天真了,嘿嘿/斜眼笑。

2.什麼是在元素被插入之前,這個插入是插入到什麼地方

爲什麼我會有這個問題呢?因爲v-if和v-show的區別大家應該都知道v-if是通過DOM的增刪改變的顯示隱藏,但是v-show呢?他可是通過display來顯示和隱藏的啊,如果你說你只可以用v-if那是插入還差不多,但是你如果用的是v-show也可以達到效果,但是那你的文檔的定義感覺有點問題啊是把?後來我發現我天真了,爲什麼呢?因爲其實我們知道除了DOM樹,還有一個瀏覽器的--渲染樹,什麼是渲染樹呢?這裏有我找的一篇文章,渲染樹其實就是一個依賴DOM樹,先有DOM樹,再根據DOM去生成瀏覽器是渲染樹,再文章中說了一句很關鍵的話:如果元素的display屬性被設置成了none,或者如果元素的子孫繼承了display:none,renderer不會被創建。節點的子類和display屬性一起決定爲該節點創建什麼樣的渲染器,說明了其實就算是v-show爲false他的DOM依然在,但是也是是單單在DOM樹上,在瀏覽器的渲染樹上是不存在的所以纔有了插入的在一個說法,並且第一個問題的進入/離開也有了很好的介紹,就是進入離開渲染樹

3.當我們自身元素的css樣式和v-enter,v-enter-to...是否會發出重複呢

  1. 重複是否會出錯

  2. 發生覆蓋,那麼誰覆蓋誰

這裏我建議當我們要過渡一個元素的屬性的時候,我們不要再這個元素上定義這個屬性值

案例

過渡改變div的高度

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>Document</title>
  <script src="./node_modules/vue/dist/vue.js"></script>
  <style>
    .box{
      border: 1px solid saddlebrown;
      background-color: brown;
    }
    .box p{
      margin: 0;
      height: 156px;
      border: 1px solid saddlebrown;
    }
    .bounce-enter-active,.bounce-leave-active {
      transition: all 1s ease;
    }
    .bounce-leave,.bounce-enter-to{
      height: 156px;
    }
    .bounce-enter,.bounce-leave-to {
      height: 0;
      color: chartreuse;
    } 
  </style>
</head>

<body>
  <div id="example-2">
    <button @click="show = !show">Toggle show</button>
    <transition name="bounce">
      <div class="box" v-show='show'>
        <p>我的高度我156px;</p>
      </div>
    </transition>
  </div>
  <script>
    new Vue({
      el: '#example-2',
      data: {
        show: false
      }
    })
  </script>
</body>

</html>

這個案例是正常的情況,但是你們是否有注意到其實我這裏的高度是設置再v-enter上面的?因爲當我們設置再v-enter下面的時候就會出現問題?其實答案很簡單就是樣式發生了覆蓋,導致高度一直都是156px還怎麼過渡對吧,覆蓋是根據css文件中樣式書寫的順序,不是HTML上的順序,大家可以去放下去試一下

  <style>
   
    /* .box p{
      margin: 0;
      height: 156px;
      border: 1px solid saddlebrown;
    } */
    .bounce-enter-active,.bounce-leave-active {
      transition: all 1s ease;
    }
    .bounce-leave,.bounce-enter-to{
      height: 156px;
    }
    .bounce-enter,.bounce-leave-to {
      height: 0;
      color: chartreuse;
    } 
    
    .box{
      border: 1px solid saddlebrown;
      background-color: brown;
      height: 156px;
    }
  </style>

也可以去打開F12去看樣式中有被下劃線,因爲替代而被下劃的樣式;

4.v-if和v-show的區別

再vue中的javaScriot鉤子函數(enter等下面的那些)監聽的是瀏覽器渲染樹中結構,所以v-if和v-show的區別其實是

v-if:先生成DOM樹瀏覽器渲染樹中的那個結構也是新生成的;

v-show:是修改了DOM樹,瀏覽器中的渲染樹是去更新渲染樹

那麼注意區分的原因是什麼,當我們去控制一個div的時候如果div中的數據有用JavaScriot鉤子函數(enter等下面的那些)監聽

的時候很有可能v-if他會再第一次監聽不到,因爲再第一次生成DOM樹的時候連第一次的數據也一同傳給了渲染樹,在vue中,數據和DOM是異步同時執行,但是DOM要等裏面的數據好了纔算OK,所以可能再第一次監聽那個div中的數據跟新的時候就監聽不到,因爲第一次我們是希望監聽的是沒數據到數據的添加的這個事件;而用v-show那麼div在DOM樹上就一直存在,那麼在瀏覽器渲染樹上也就一次存在,當第一次數據改變我們就只是數據改變就OK了

解決問題:那麼我們如果解決問題呢?我們只需要讓DOM樹生成的過程中不要代第一次的數據,讓那個div中改變數據的行爲代碼在下一幀執行,就可以了,那麼DOM樹就是先有了那個DIV,在是在下一幀添加數據就和v-show的表現形式一樣了,那麼這個再下一幀的方法就是$nextTick();

 

動畫

爲什麼這裏不用謝v-enter呢? 我們想一下其實我們動畫裏面是包含了開始狀態和結束狀態的,我們需要的只是執行那個動畫,不用想過渡一樣定義過渡的開始和結束值

<!DOCTYPE html>
<html>
 
<head>
  <meta charset="utf-8">
  <title>Vue中css動畫的原理</title>
  <script src="./node_modules/vue/dist/vue.js"></script>
  <style>
    @keyframes bounce {
      0% {
        transform: scale(0);
      }
 
      50% {
        transform: scale(1.5);
      }
 
      100% {
        transform: scale(1);
      }
    }
 
    /* .fade-enter-active和.fade-leave-active代表一直都在的那個時間點 */
    .fade-enter-active {
      transform-origin: left center;
      /* 這裏寫這個因爲div太寬了 */
      animation: bounce 1s;
    }
 
    .fade-leave-active {
      transform-origin: left center;
      animation: bounce 1s reverse;
    }
  </style>
</head>
 
<body>
  <div id="root">
    <transition name="fade">
      <div v-if="show">hello world</div>
    </transition>
    <button @click="click">切換</button>
  </div>
  <script>
    var root = new Vue({
      el: '#root',
      data: {
        show: true
      },
      methods: {
        click: function () {
          this.show = !this.show;
        }
      }
    })
  </script>
 
</body>
 
</html>

這裏你會發現動畫沒寫v-enter和v-leave-to爲什麼呢?

因爲他是動畫啊它不需要像過濾一樣有初始和結束的差別來判斷,他只需要知道什麼時候執行v-enter-active 和v-leave-active
再執行裏面的語句就可以了      

JavaScript鉤子函數

除了用CSS過渡的動畫來實現vue的組件過渡,還可以用JavaScript的鉤子函數來實現,在鉤子函數中直接操作DOM。我們可以在屬性中聲明以下鉤子:

<transition
  v-on:before-enter="beforeEnter"
  v-on:enter="enter"
  v-on:after-enter="afterEnter"
  v-on:enter-cancelled="enterCancelled"
  v-on:before-leave="beforeLeave"
  v-on:leave="leave"
  v-on:after-leave="afterLeave"
  v-on:leave-cancelled="leaveCancelled"
>
</transition>
//這裏的進入還是要強調一下是瀏覽器的渲染樹裏面

methods: {
  // 過渡進入
  // 設置過渡進入之前的組件狀態
  beforeEnter: function (el) {
    // ...
  },
  // 設置過渡進入完成時的組件狀態
  enter: function (el, done) {
    // ...
    done()
  },
  // 設置過渡進入完成之後的組件狀態
  afterEnter: function (el) {
    // ...
  },
  enterCancelled: function (el) {
    // ...
  },
  // 過渡離開
  // 設置過渡離開之前的組件狀態
  beforeLeave: function (el) {
    // ...
  },
  // 設置過渡離開完成時地組件狀態
  leave: function (el, done) {
    // ...
    done()
  },
  // 設置過渡離開完成之後的組件狀態
  afterLeave: function (el) {
    // ...
  },
  // leaveCancelled 只用於 v-show 中
  leaveCancelled: function (el) {
    // ...
  }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章