Vuetifyを使ってカードの端からニュっと出てくるリンクを作ってみた

2021.05.28

はじめに

現在、私が開発を担当をしているサービス(Proflly※)の開発に関する話です。
※ 参考: 開発の経緯などはこちらのブログにかかれています↓

クラスメソッドが抱えていた組織の悩みを解決したProflly

一覧ページのカードをポイントした時に、詳細ページへのリンクがニュっと表示されるようになっています。 コレの作り方についてのブログです。

なぜ記事をかいたかというと、個人的にちょっと苦労したためです。
苦労した理由は、Vuetify(利用しているUIフレームワーク)の標準オプションだけでは実現できなかったためです。
同じような事をしたい方の参考になればいいなと思ったのと、自分の備忘録も兼ねて、失敗も含めてやりかたとブログ化をすることにしました。 結論だけみたい方はまとめをご覧ください。

やってみたこと

カードの作成

まずは必要なタグとスタイルを定義します。

その上で、詳細ページへのダミーリンクを作成します。

ダミーリンクは、とりあえずダイアログを表示するだけのものにします。

<template>
  <v-app>
    <v-card width="365" height="168" :elevation="1">
      <v-list-item>
        <v-list-item-avatar size="80" color="grey"></v-list-item-avatar>
        <v-list-item-content>
          <div class="name">ほげ太郎</div>
          <div class="dpt">開発部</div>
        </v-list-item-content>
      </v-list-item>
      <v-card-actions>
        <div class="show-detail">
          <v-btn icon color="white" onClick="alert('ページ遷移')">
            <v-icon>mdi-account</v-icon>
          </v-btn>
        </div>
      </v-card-actions>
    </v-card>
  </v-app>
</template>

<style lang="scss" scoped>
$button-height: 36px;

.show-detail {
  position: absolute;
  right: 0;
  top: 84px - $button-height / 2;

  height: $button-height;
  background-color: grey;
  border-radius: 17px 0 0 17px;

  transform: translate(0, 0);
  transition-property: all;
  transition-duration: 200ms;
  transition-timing-function: ease;

  &:hover {
    background-color: #111;
  }
}
</style>

これで、まだエフェクトはないものの必要なボタン等の配置はできました。

動作画面:

hoverコンポーネントの追加

次にエフェクトの実装を進めました。

カードをホバーした時にエフェクトを行うため、v-cardコンポーネントの親側にhoverコンポーネントを追加します。

ホバーによってスタイリングを変更するため、ボタンの親タグにクラス・スタイルのバインディングを追加します。

ホバー時・非ホバー時のスタイルをそれぞれ定義します。

<template>
  <v-app>
    <v-hover v-slot:default="{ hover }">
      <v-card width="365" height="168" :elevation="1">
        <v-list-item>
          <v-list-item-avatar size="80" color="grey"></v-list-item-avatar>
          <v-list-item-content>
            <div class="name">ほげ太郎</div>
            <div class="dpt">開発部</div>
          </v-list-item-content>
        </v-list-item>
        <v-card-actions>
        <div class="show-detail" :class="hover ? 'effect-in' : 'effect-fade'">
            <v-btn icon color="white" onClick="alert('ページ遷移')">
              <v-icon>mdi-account</v-icon>
            </v-btn>
          </div>
        </v-card-actions>
      </v-card>
    </v-hover>
  </v-app>
</template>

<style lang="scss" scoped>
$button-height: 36px;

.show-detail {
  position: absolute;
  right: 0;
  top: 84px - $button-height / 2;

  height: $button-height;
  background-color: grey;
  border-radius: 17px 0 0 17px;

  transform: translate(0, 0);
  transition-property: all;
  transition-duration: 200ms;
  transition-timing-function: ease;

  &:hover {
    background-color: #111;
  }
}

.effect-fade {
  opacity: 0;
  width: 0;
}

.effect-in {
  opacity: 1;
  width: 36px;
}
</style>

動作画面:

ホバーの調整

これは失敗談なんですが、前ステップで漏れがありました。

エフェクトは動作するようになりましたが、アニメーション中にホバーすると開く・閉じるを繰り返すようになってました。。

閉じる場合には、ホバーのイベントがトリガされないようにする必要がありました。

なので、閉じる場合のスタイル定義に pointer-events: none; を追加しました。

<template>
  <v-app>
    <v-hover v-slot:default="{ hover }">
      <v-card width="365" height="168" :elevation="1">
        <v-list-item>
          <v-list-item-avatar size="80" color="grey"></v-list-item-avatar>
          <v-list-item-content>
            <div class="name">ほげ太郎</div>
            <div class="dpt">開発部</div>
          </v-list-item-content>
        </v-list-item>
        <v-card-actions>
        <div class="show-detail" :class="hover ? 'effect-in' : 'effect-fade'">
            <v-btn icon color="white" onClick="alert('ページ遷移')">
              <v-icon>mdi-account</v-icon>
            </v-btn>
          </div>
        </v-card-actions>
      </v-card>
    </v-hover>
  </v-app>
</template>

<style lang="scss" scoped>
$button-height: 36px;

.show-detail {
  position: absolute;
  right: 0;
  top: 84px - $button-height / 2;

  height: $button-height;
  background-color: grey;
  border-radius: 17px 0 0 17px;

  transform: translate(0, 0);
  transition-property: all;
  transition-duration: 200ms;
  transition-timing-function: ease;

  &:hover {
    background-color: #111;
  }
}

.effect-fade {
  opacity: 0;
  width: 0;
  pointer-events: none;
}

.effect-in {
  opacity: 1;
  width: 36px;
}
</style>

動作画面:

Profllyへの組み込み

ここまでで、詳細ページへのリンクと、そのリンクをいい感じに見せるためのエフェクトを付ける方法が分かりました。

それらをProfllyに組み込みました。

最終的にこんな形になっています。

  • プロフィールのカード(完成形)

まとめ

  • Vuetifyのv-cardのホバー時にリンクをアニメーション表示するには、hoverコンポーネントとクラス・スタイルのバインディングを利用すれば簡単に実装できます。
    • サンプルコード
              <template>
                <v-app>
                  <v-hover v-slot:default="{ hover }">
                    <v-card width="365" height="168" :elevation="hover ? 12 : 1">
                      <v-list-item>
                        <v-list-item-avatar size="80" color="grey"></v-list-item-avatar>
                        <v-list-item-content>
                          <div class="name">ほげ太郎</div>
                          <div class="dpt">開発部</div>
                        </v-list-item-content>
                      </v-list-item>
                      <v-card-actions>
                      <div class="show-detail" :class="hover ? 'effect-in' : 'effect-fade'">
                        <v-btn icon color="white" onClick="alert('ページ遷移')">
                          <v-icon>mdi-account</v-icon>
                        </v-btn>
                      </div>
                      </v-card-actions>
                    </v-card>
                  </v-hover>
                </v-app>
              </template>
      
              <style lang="scss" scoped>
              $button-height: 36px;
      
              .show-detail {
                position: absolute;
                right: 0;
                top: 84px - $button-height / 2;
      
                height: $button-height;
                background-color: grey;
                border-radius: 17px 0 0 17px;
      
                transform: translate(0, 0);
                transition-property: all;
                transition-duration: 200ms;
                transition-timing-function: ease;
      
                &:hover {
                  background-color: #111;
                }
              }
      
              .effect-fade {
                opacity: 0;
                width: 0;
                pointer-events: none;
              }
      
              .effect-in {
                opacity: 1;
                width: 36px;
              }
      
              </style>

さいごに

2021/5/28現在、Profllyは現在クローズドβ版を公開中です。 もし、こちらにご興味があれば以下サイトを見てもらえると嬉しいです。 https://classmethod.jp/m/proflly/

参考