# ローディングと高さのアニメーション

# デモ

DEMO

    LOADING NOW

    # 使用している主な機能

    算出プロパティ computed 120ページ

    ウォッチャ watch 128ページ

    nextTick 143ページ

    コンポーネント 146ページ

    動的コンポーネント 185ページ

    トランジション 194ページ

    # ソースコード

    index.vue
    <template>
      <div class="example-loading example">
        <p><button @click="loadContent" :disabled="!list.length">コンテンツをリロード</button></p>
        <!-- ボーダー付きのラッパーレイヤー -->
        <div class="flexbox-wrapper" :style="{height: height+'px'}">
          <!-- トランジション & $refs.body -->
          <ul class="flexbox-body" ref="body">
            <li v-for="item in list" :key="item.id">
              {{ item.name }} {{ item.price }}
            </li>
          </ul>
          <transition>
            <Loading v-if="!list.length"/>
          </transition>
        </div>
      </div>
    </template>
    
    <script>
    import axios from 'axios'
    import Loading from './Loading.vue'
    export default {
      components: { Loading },
      data() {
        return {
          height: 0,
          list: []
        }
      },
      // ウォッチャ
      watch: {
        list() {
          // nextTick
          this.$nextTick(() => {
            // $refs
            this.height = this.$refs.body.getBoundingClientRect().height
          })
        }
      },
      methods: {
        loadContent() {
          this.list = []
          axios.get('/data/list.json').then(response => {
            setTimeout(() => {
              this.list = response.data
            }, 1500)
          })
        }
      },
      created() {
        this.loadContent()
      }
    }
    </script>
    
    <style scoped>
    .flexbox-wrapper {
      position: relative;
      border: 2px solid #ccc;
      border-radius: 4px;
      overflow: hidden;
      transition: height .4s;
      min-height: 3em;
    }
    .flexbox-body {
      margin: 0 0 0 24px;
      padding: 16px;
    }
    /* トランジション用スタイル */
    .v-enter-active, .v-leave-active {
      transition: opacity .4s;
    }
    .v-enter, .v-leave-to {
      opacity: 0;
    }
    </style>
    
    LoadContent.vue
    <template>
      <div class="before-load-content">
        LOADING NOW
      </div>
    </template>
    
    <style scoped>
    .before-load-content {
      position: absolute;
      top: 0;
      left: 0;
      display: flex;
      align-items: center;
      justify-content: center;
      width: 100%;
      height: 100%;
      color: #bbb;
    }
    </style>
    

    # コメント

    Katashin さんの vue-size-provider を利用すると、要素の高さを監視して簡単に高さのアニメーションを適用できます。