Vue 的 transition & 實現路由類 Tab 左右滑動切換的效果

Vue 的 transition & 實現路由類 Tab 左右滑動切換的效果

先說下 transition 爲何可讓你定義了 v-enter, v-enter-active 以後就能夠觸發transition.
實際過程按個人理解應該是這樣:javascript

  1. 最開始的時候, 先給元素加上了 v-enter, v-enter-active 兩個classcss

  2. 在下一幀的時候, 刪掉 v-enter 這個class.html

  3. 在過渡結束以後, 再刪掉 v-enter-active.java

對於2的解釋:ide

  • 這個幀的概念我剛開始沒理解, 可是實際上能夠理解成 '一段時間以後';this

  • 你刪掉 v-enter 會致使什麼狀況?
    元素的樣式會變化code

那麼元素如今只有定義在本身身上的樣式了
因此要變回去
而後發現有定義在 v-enter-active 上面的過渡效果
就會應用過渡效果orm

覆盤一下過程:
剛開始的時候, 元素有本身的樣式, 有 v-enter, v-enter-active 中定義的樣式.
在一段時間間隔, 好比說 100ms 以後, 刪掉了 v-enter, 意味着元素的樣式變化。
變化, 而後發現存在 transition的定義, 就應用 transition,
這就造成了咱們最終看見的 transition效果.router

給個demo:htm

.box {
  height: 100px;
  width: 100px;
  background: red;
}
.v-enter {
  height: 200px;
  width: 200px;
}
.v-enter-active {
  transition: all 2s;
}
<div class="box"></div>
var box = document.querySelector('.box');

    box.classList.add('v-enter');
    box.classList.add('v-enter-active');

    setTimeout(function(){
      box.classList.remove('v-enter');
    }, 100);

再說下元素從顯示到消失的時候
咱們知道, 若是過渡效果的終點是 display:none, 那麼過渡效果是不會生效的, 因此我以爲
v-if, v-show 對過渡效果都是有所控制的, 它們應該是在 transitionEnd 的時候纔去應用
display:none; 或者移除元素.

可是元素離開和元素進入還有點不同:

你的元素在離開的時候, 元素是已經存在於頁面上, 是你已經能看見的
而後你給它加上 v-leave, v-leave-active
按照以前的邏輯, v-leave 有樣式, v-leave-active 裏面有 transition
元素的樣式變動-> 觸發 transition, 因此加上就直接觸發 transition, 還等個什麼下一幀。
既然加上就觸發 transition, 那你要 v-leave 幹嗎, 爲何不直接把
樣式和 transition 都加在 v-leave-active 上面呢。

暫時沒有發現 v-leave 的做用, 感受不是必須的, 就是對稱同樣. 或者爲了樣式分離.

transition 過渡效果的樣式其實是有通用規律的:

.v-enter {
  opacity:0;
}
.v-enter-active {
  transition: all 1s;
}
.v-leave-active {
  opacity: 0;
  transition: all 1s;
}

更常見的寫法是這樣:

.v-enter {
  opacity:0;
}
.v-enter-active, .v-leave-active {
  transition: all 1s;
}
.v-leave-active {
  opacity: 0;
}

關於 transition 的一個應用: 實現路由 類 Tab 左右滑動切換的效果.

類 Tab 左右滑動切換的效果,就是這樣:

[viewport]
      [router1]   [router2]

router1,2 左右拉來拉去, 就是左右滑動切換的效果.

那咱們的問題就能夠變成:
把當前的路由 router1, 和下一個路由 router2, 並列放到一行,
用戶點擊跳轉的的時候, 同時滑動 router1,router2

可是直覺都告訴咱們, 路由壓根就不是這麼排列的, 當你在 router1 的時候, router2 根本就不存在啊.
不存在何來並排.

可是想一想咱們以前說的, 加上 transition 以後, 元素消失會怎麼辦?
元素先應用 transition, transitionEnd 的時候, 元素纔會消失.

這個的意思就是說:
跳轉的一瞬間, 當前的 route1 會開始應用 transition, 尚未消失於頁面之上.
而後下一個 router2 已經建立, 已經存在於頁面之上.
此時, 兩個 router 都是存在的.

這就是時機.
先說下咱們的 DOM 結構

<transition>
      <router-view></router-view>
    <transition>
  1. 咱們要先讓兩個 router 並排, how ?
    定位啊:

.router-view {
  position: absolute;
  top: 0;
  left: 0;
}

按理說兩個 router 都是 left:0, top:0, 應該是重疊的是否是?
對.
因此咱們對要進入的那個 router 作下 translate
好比當前的是 router1, 點擊要向前跳轉到 router2, 那麼對 router2 translateX(100%);
這樣兩個 router 是否是就並排了.

並排以後就是動起來, 也就是應用滑動效果.
兩個組件都是被 transition 包裹起來因此只要定義相應的class就能夠了.

先說向前進:
假設 transition 的 name = 'slide-forward'

對於 router1:
start: 是當前的位置
end: 是當前位置的 translateX(-100%), 也就是當前位置的左邊.

對於 router2:
start: 是相對於當前位置的 translateX(100%);
end: 是當前位置.

// router1
.slide-forward-leave-active {
  transition: all 1s;
  transform: translate(-100%);
}
// router2
.v-enter {
  transform: translateX(100%);
}
.v-enter-active {
  transition: all 1s;
}

再說後退, 設 transition 的 name = 'slide-back';
class就是:

// router1
.v-enter {
  transfrom: translateX(-100%);
}
// router2
.v-enter-active {
  transition: all 1s;
}
.v-leave-active {
  transfrom: translateX(100%);
  transition: all 1s;
}

整理一下, 獲得的兩個 transition,

.slide-forward-enter {
  transform: translate(100%);
}
.slide-forward-enter-active {
  transition: all 1s ease-in-out;
}
.slide-forward-leave-active {
  transform: translate(-100%);
  transition: all  1s ease-in-out;
}


.slide-back-enter {
  transform: translate(-100%);
}
.slide-back-enter-active {
  transition: all 1s ease-in-out;
}
.slide-back-leave-active {
  transform: translate(100%);
  transition: all  1s ease-in-out;
}

如今再討論一下: 咱們該如何判斷當前是前進仍是後退呢?
下面這樣:

watch: {  
    '$route' (to, from) {  
      if (!this.map[to.path]) {
        this.map[to.path] = +new Date() + 1;
      }
      if (!this.map[from.path]) {
        this.map[from.path] = +new Date();
      }

      if (this.map[to.path] > this.map[from.path]) {
        this.transitionName = 'slide-forward';
      } else {
        this.transitionName = 'slide-back'
      } 
    }  
  }
相關文章
相關標籤/搜索