Try   HackMD

多個 元素 / 元件 的轉場

竹白記事本
Vue Transition|目錄

tags: Vue Transition 竹白的 Vue.js 學習筆記

多個元素的轉場

<transition> 也可以用在多個元素的轉場。

舉例來說:

<transition>
  <table v-if="items.length > 0">
    <!-- ... -->
  </table>
  <p v-else>Sorry, no items found.</p>
</transition>

但要注意,Vue 在切換畫面時,並不會完全置換元素,會使用一種最大限度減少動態元素並且儘可能的嘗試修復/再利用相同類型元素的算法。

因此當有相同標籤的元素在做切換時,需要使用 key 特性設置唯一的值來標記以讓 Vue 區分它們。

<transition>
  <button v-if="isEditing" key="save">
    Save
  </button>
  <button v-else key="edit">
    Edit
  </button>
</transition>

在一些場景中,也可以通過給同一個元素的 key 特性設置不同的狀態來代替 v-ifv-else,上面的範例可以重寫為:

<transition>
  <button v-bind:key="isEditing">
    {{ isEditing ? 'Save' : 'Edit' }}
  </button>
</transition>

使用多個 v-if 的多個元素的轉場可以重寫為綁定了動態屬性的單個元素轉場。例如:

<transition>
  <button v-if="docState === 'saved'" key="saved">
    Edit
  </button>
  <button v-if="docState === 'edited'" key="edited">
    Save
  </button>
  <button v-if="docState === 'editing'" key="editing">
    Cancel
  </button>
</transition>

可以重寫為:

<!-- .html -->
<transition>
  <button :key="docState">
    {{ buttonMessage }}
  </button>
</transition>
// ...
computed: {
  buttonMessage: function () {
    switch (this.docState) {
      case 'saved': return 'Edit'
      case 'edited': return 'Save'
      case 'editing': return 'Cancel'
    }
  }
}

1. 轉場模式

請考慮以下程式碼:

<transition>
  <button :key="isEditing" @click="isEditing = !isEditing">
    {{ isEditing ? 'On' : 'Off' }}
  </button>
</transition>

在 on 按鈕和 off 按鈕的轉場中,兩個按鈕都被重繪了,一個離開轉場的時候另一個開始進入轉場。這是 <transition> 的預設行為,進入和離開同時發生。

你可能會想到,可以加上 position: absolute,因為兩者重疊了,所以不會產生元素位移的情況:

button {
  position: absolute;
}

但如果加上 translate 讓它們運動像滑動,還是會有兩個元素同時出現的破綻:

.v-enter,
.v-leave-to {
  opacity: 0;
  transform: translateX(100%);
}

同時生效的進入和離開的轉場不能滿足所有要求,所以 Vue 提供了轉場模式:

  • in-out:新元素先進行轉場,完成之後當前元素轉場離開。
  • out-in:當前元素先進行轉場,完成之後新元素轉場進入。

加上 mode="out-in" 的效果:

<transition mode="out-in">
  <button :key="isEditing" @click="isEditing = !isEditing">
    {{ isEditing ? 'On' : 'Off' }}
  </button>
</transition>
.v-enter-active, .v-leave-active {
  transition: 1.5s opacity;
}

in-out 模式的範例:

button {
  position: absolute;
}

.v-enter,.v-leave-to {
opacity: 0;
}

.v-enter {
  transform: translateX(100%);
}

.v-leave-to {
  transform: translateX(-100%);
}

多個元件的轉場

多個元件的轉場簡單很多,我們不需要使用 key 特性。只需要使用 動態切換 元件:

<!-- .html -->
<div id="app">
  <input type="radio" value="v-a" v-model="view" />A
  <input type="radio" value="v-b" v-model="view" />B
  <transition name="component-fade" mode="out-in">
    <component v-bind:is="view"></component>
  </transition>
</div>
.component-fade-enter,
.component-fade-leave-to {
  opacity: 0;
}

.component-fade-enter-active,
.component-fade-leave-active {
  transition: opacity 0.3s ease;
}

const vm = new Vue({
  el: '#app',
  data: {
    view: 'v-a',
  },
  components: {
    'v-a': {
      template: '<div>Component A</div>',
    },
    'v-b': {
      template: '<div>Component B</div>',
    },
  },
});