tifyでQiita風UIを作る - チーム切り替えメニュー


「VuetifyでQiita風のコンポーネントを作る」、今回はヘッダーのチーム切り替えメニュー編です。
目的やVuetifyの説明、他のコンポーネントについてはこちら

チーム切り替えメニューとは

ロゴの右側にある、下三角から開けるメニューのことです。(命名は勝手にしました。)
Qiita:Teamに所属していない方にはあまり馴染みのないものかもしれませんが、
Qiita:Teamにログインしていると、このメニューから切り替えることができます。

実際のイメージはこのような感じです。

Qiita:Teamにログインしているとき

Qiita:Teamにログインしていないとき

Vuetifyで実装

まずはCodepenで作ったサンプルを紹介。

See the Pen Vuetify Qiita風Team切り替えメニュー by totto357 (@totto357) on CodePen.

SFCで表現するとこちら。

<template lang="pug">
// チーム切り替えメニュー
v-menu(offset-y nudge-bottom="16px")

  // activator 
  v-sheet.mr-2(slot="activator" color="green darken-2")
    v-icon arrow_drop_down

  // 別のチームにログインしている 
  v-card(v-if="isLoginToTeam" width="300px")
    v-list(dense)
      v-subheader ログイン中のチーム
      template(v-for="team, i in teams")
        v-divider.my-1(v-if="i!=0" inset)
        v-list-tile(avatar @click="" :key="team.name")
          v-list-tile-action
            v-icon(v-if="team.view") mdi-check
          v-list-tile-content
            v-list-tile-title {{ team.name }}
          v-spacer
          v-layout(align-center justify-end)
            v-avatar(size="20px")
              v-img(:src="team.user.img")
            span.ml-1 {{ team.user.name }}
      v-divider.my-1
      v-list-tile(avatar @click="")
        v-list-tile-action
          v-icon mdi-exit-to-app
        v-list-tile-content
          v-list-tile-title 別のチームにログイン...

  // 別のチームにログインしていない
  v-card(v-else width="250px")
    v-list(dense)
      v-list-tile(avatar @click="" )
        v-list-tile-action
          v-icon mdi-check
        v-list-tile-content
          v-list-tile-title Qiita
      v-divider.my-1
      v-subheader ログイン中のチームがありません
      v-list-tile(avatar @click="")
        v-list-tile-action
          v-icon mdi-exit-to-app
        v-list-tile-content
          v-list-tile-title Qiita:Team にログイン...
</template>

<script lang="ts">
import Vue from 'vue'
export default Vue.extend({
  data: () => ({
    isLoginToTeam: true,
    teams: [
      { view: false, name: "HogeTeam", user: { name: "totto357", img: "https://qiita-image-store.s3.amazonaws.com/0/97227/profile-images/1516012241" }},
      { view: true, name: "Qiita", user: { name: "totto357", img: "https://qiita-image-store.s3.amazonaws.com/0/97227/profile-images/1516012241" }},
    ],
  }),
})
</script>

Tips

  • v-menuv-dialogなどを表示する際のトリガーとなるボタンやテキストは、activatorというスロットを通して表現することができる
  • offset-ynudge-bottomでヘッダーの下部とメニューの上部が揃うように位置調整
  • v-sheetは高さと幅を自由に設定できるので、わりと重宝する
    • v-cardのベースにもなってるコンポーネント
    • 公式のサンプルはあまりないけど、自由度が高いので好きに使える
  • Qiita:Teamでログインしているかどうかの切り替えはv-ifを使って切り替えを行う
  • 区切り線として利用するv-dividerinsetというプロパティで幅を調整することができる
  • v-list-tile-actionの幅が広すぎると感じたら無理に使わなくてもよい
  • v-iconFont AwesomeMaterial Design Icons 使えるので、Material Iconsに合うものがなければ探してみるといいかも

v-menuでよく使うプロパティ

今回のようにVuetifyでメニューを表示するのに利用するv-menuですが、いろんなプロパティを設定することができます。
その中でも自分がよく使うプロパティを紹介したいと思います。

close-delay

メニューが閉じるまでの時間を制御することができます。
基本的には後述するopen-on-hoverと利用することが多いかも。

例えば、ホバーで開くメニューがあって、デザイン上activatorとメニューをちょっと離している場合、
activatorからメニューにカーソルを移動するとホバーが外れてしまうのでメニュー閉じてしまうことがあります。
そんな時に、メニューが閉じるまでのディレイを設定することでメニューが閉じないように制御することができます。

close-on-content-click

メニューのコンテンツ部分(デフォルトスロットで渡したコンポーネント)をクリックしたときにメニューを閉じるかどうかを制御できます。
リンクしかないメニューであれば問題ないですが、何かを入力してもらいたいようなメニューだとクリックで閉じてしまうと困ります。
そんなときにclose-on-content-clickfalseに設定すると、クリックしてもメニューが開いたままになります。

デフォルトはtrueなので、クリックしても閉じるようになっています。

nudget-系

activatorに対してメニューの位置をどの程度ずらすのか設定することができます。
例えばnudge-bottomであれば、メニューを表示する起点から下方向にどれだけずらすのかを指定できます。
(起点はデフォルトではactivatorの左上。後述のoffset-系で変更できる。)

今回の「チーム切り替えメニュー」ではヘッダーの下部とメニューの上部を合わせたかったので、
nudge-bottom16pxを指定しています。

offset-x, offset-y

メニューを表示する起点を変更することができます。
offset-xを指定すると、x軸の起点がactivatorの左から右に変更されます。
offset-yを指定すると、y軸の起点がactivatorの上から下に変更されます。
つまり、まとめると以下となります。

  • なし: 左上
  • offset-xのみ: 右上
  • offset-yのみ: 左下
  • 両方: 右下

open-on-hover

カーソルをactivatorにホバーさせるだけで、メニューを開くかどうかを制御できます。
close-delayでも書きましたが、nudge-系を使ってるときにはカーソル移動でメニューが消えてしまうことがあるので、注意が必要です。