Vue.js transition-group

by uto usui

HTML

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.6.1/css/bulma.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
<div id="app">
  <div class="field has-addons">
    <p class="control">
      <button class="button" @click="toggle">
        {{show ? 'leave' : 'enter'}}
      </button>
    </p>
    <p class="control">
      <button class="button" @click="add">
        add
      </button>
    </p>
    <p class="control">
      <button class="button" @click="shuffle">
        shuffle
      </button>
    </p>
  </div>
  <div class="field">
    <label class="label">Image Query</label>
    <div class="control">
      <input class="input" type="text" placeholder="Text input" v-model="query">
    </div>
    <p class="help is-info">Enter the keyword of the image you want to call.</p>
  </div>
  
  <transition-group name="fade" tag="ul" class="columns is-mobile is-multiline is-gapless">
    <li class="column is-one-third" v-show="show" v-for="item in items" :key="item.src">
      <img :src="item.src" alt="placeholder">
    </li>
  </transition-group>
  
</div>

SCSS

// 位置の変化を検知する *-move 
.fade-move {
  transition: all 1s cubic-bezier(0.895, 0.03, 0.685, 0.22);
}

// enter の活性状態。トランジションに入るフェーズ中に適用。
// 要素が挿入される前に追加され、トランジション/アニメーションが終了すると削除
// 期間、遅延、およびイージングカーブを定義
.fade-enter-active {
  // easeOutExpo
  transition: all 1s cubic-bezier(0.19, 1, 0.22, 1);
}


// leave の活性状態。トランジションが終わるフェーズ中に適用
// leave トランジションがトリガされるとき、直ちに追加され、トランジション/アニメーションが終了すると削除
// 期間、遅延、およびイージングカーブを定義
.fade-leave-active {
  // easeInQuart
  transition: all 1s cubic-bezier(0.895, 0.03, 0.685, 0.22);
}

//  enter の開始状態。要素が挿入される前に適用され、要素が挿入された 1 フレーム後に削除
.fade-enter {
  opacity: 0;
  transform: translateX(-100%);
}

// leave の終了状態
// トランジションの終了がトリガされた後に (同時に v-leave 削除) 1フレーム追加
// トランジション/アニメーションが終了すると削除
.fade-leave-to {
  opacity: 0;
  transform: translateX(100%);
}

img {
  vertical-align: bottom;
}

Babel + JSX

let baseImageUrl = 'https://source.unsplash.com/1600x900/?';

const root = new Vue({
   
   data: function() {
     return {
       show: false,
       items: [
         {
           id: this.counter,
           src: baseImageUrl + 'nature,water'
         },
       ],
       query: '',
       counter: 0,
     }
   },

   methods: {
    toggle() {
      this.show = !this.show
    },
    add() {
      // 画像ロードするの待って
      let img = new Image();
      let src = baseImageUrl + this.query;
      img.onload = () => {
        this.items.push({
          src: src
        });
      };
      img.src = src;
    },
    shuffle() {
      this.items = _.shuffle(this.items)
    }
  }

});

root.$mount( '#app' );