0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Vue.jsですべての要素をアニメーションの対象にする

Last updated at Posted at 2022-10-31

※※※ 個別の要素を繊細に制御したい場合はdata属性を持たせるなどの別記事を探して参照した方がよい。この記事は大変大雑把な挙動を実装するためのものです。 ※※※

ユーザー動作(テキストフォームの検索実行や、チェックボックスのチェック挙動)のたびに一覧領域をすべてリフレッシュ→その後アニメーションでふわっと表示させるという表現をしたい。

index.html
<transition-group name="fade" tag="div" appear>
  <template v-if="items.length">
    <article v-for="(item,index) in items" v-bind:key="item.id">
      ...
    </article>
  </template>
</transition-group>

しかしVue.jsは再描画をなるべく避ける指向のライブラリであるためか、ユーザー動作の前後で変化のない要素がアニメーションにならない。
色々探しても「一度全部消す」という表現に使えそうなやり方がtransition-groupコンポーネントで見つからない。
必ずしも全ての要素に対してVue.jsのtransitionが走るとは限らないので、Vue.jsのtransitionから一旦離れて考えてみる。素朴なCSSアニメーションで組んでみる。

script.js
new Vue({
  el: '#app',
  data: {
    animeFlg : false,
  },...
  computed: {
    items: function() {
      let arr = [];
      this.animeFlg = true;
      ...絞り込み処理...
      setTimeout(function(){
        if(this.animeFlg){
          this.animeFlg = false;
        }
      },500);
      return arr;
    }
  }
});

itemsは算出プロパティなので
1.算出プロパティが走るたびにCSSアニメーション用のフラグをtrueにする
2.returnの直前でsetTimeout()を使い、return後にCSSアニメーション用のフラグをfalseにする

index.html
<div :class="{ 'refresh-fade' : animeFlg }">
  <template v-if="items.length">
    <article v-for="(item,index) in items" v-bind:key="item.id">
      ...
    </article>
  </template>
</div>

3.一覧のラッパー要素のクラスをデータバインディングにして、アニメーション用フラグの状態によってクラスを制御する

style.css
@keyframes refresh-fade {
  0% {
    opacity: 0;
  }
  10% {
    opacity: 0;
  }
  100% {
    opacity: 1;
  }
}
.refresh-fade {
  animation: refresh-fade 1s;
}

4.transitionでもいいが制御しやすいのでanimationで指定

これで全体が一度リフレッシュ→フェードされるように見える。とりあえずは望んだ動作になった。
(せっかくのVue.jsのtransition機能を無下にする仕上がり…)

ただこれだと「もっと見る」ボタンなどを押したときの挙動も全体がリフレッシュされるように見えてしまうので、divを再度transition-groupにし、部分動作の際のVue.jsのtransitionを実装する。詳しくは以下の過去記事を参照。
https://qiita.com/c_nnnnnn/items/900f1f8af53f139df92a

index.html
<transition-group tag="div" :class="{ 'refresh-fade' : animeFlg }" :name="showMoreAnimeFlg ? 'cat-fade' : 'cat-no-fade'" @after-enter="deAnimate" @after-leave="deAnimate">
  <template v-if="items.length">
    <article v-for="(item,index) in items" v-bind:key="item.id">
      ...
    </article>
  </template>
</transition-group>
script.js
...
methods: {
  showMoreItems:function(){//もっと見るボタンに追加されているmethod
    ...
    this.showMoreAnimeFlg = true;
  },
  deAnimate : function(){//Vueのtransition後に発火するイベント
    this.showMoreAnimeFlg = false;
  }
}
style.css
.cat-fade-enter {
  opacity: 0;
}
.cat-fade-enter-to {
  opacity: 1;
}
.cat-fade-enter-active{
  transition: opacity .5s;
}

5.もっと見るボタンクリック時に部分アニメーション用フラグをtrueにする
6.transition-groupに設定されたnameをデータバインディングにして、部分アニメーション用フラグの状態によってクラスを制御する(アニメーションと非アニメーションの切り替え)
7.JavaScriptフックでVue.jsのtransition後に部分アニメーション用フラグをfalseにする

もっとスマートな方法が多分ある。わかりません。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?