LoginSignup
5
4

More than 5 years have passed since last update.

angular-material2 を利用してリッチな DropdownButton を作る

Last updated at Posted at 2017-12-12

DropdownButton とは?

Qiita のこれですね!

スクリーンショット 2017-12-12 22.04.53.png

Qiita と同じように 限定公開 ←→ 一般公開 ...etc 的なUIが作りたくて 「どんなのが良いかなぁ」 と考えた結果、 DropdownButton なら綺麗にまとまりそう! って思ったので自作することにしました。

今回のライブ Demo はこちら → https://stackblitz.com/edit/angular-miln1y

チラ見用 gif も置いておきます

Untitled2.gif

どうやって作ろうか

とりあえずググってみると、DropdownMenu を渇望している 公式の issue を発見。

そうそう これが欲しかったんだよ!

しかし...、今のところ実装予定ではなさそうですね・・・

しゃーなぃ 自分で作るかぁ・・ ん?

  • mat-menu
  • mat-button-toggle-group

とかで実装したというコメントを発見

…なるほど、確かに組み合わせればそれっぽいのできそう!
ありがとう コメントの人!

実装してみる

html

  • だいたいこんな感じの構造かなぁ とイメージを膨らませつつ書く
<mat-menu #menu="matMenu">
    <button mat-menu-item *ngFor="let item of selectItems" (click)="onSelect(item)">
        <mat-icon *ngIf="item.icon">{{ item.icon }}</mat-icon>
        <span>{{ item.text }}</span>
    </button>
</mat-menu>

<mat-button-toggle-group class="dropdown-button" [class.dropdown-button--disabled]="isDisabled()">
    <mat-button-toggle mat-ripple [disabled]="disabled" class="dropdown-button__main" [matRippleDisabled]="isDisabled()" (click)="onClick()">
        {{ selectedItem.text }}
    </mat-button-toggle>

    <mat-button-toggle mat-ripple class="dropdown-button__trigger" [matMenuTriggerFor]="menu">
        <mat-icon>arrow_drop_down</mat-icon>
    </mat-button-toggle>
</mat-button-toggle-group>
  • mat-menu と mat-button-toggle を基本として構成
  • ripple エフェクトも angular-material から お借りしました
  • mat-ripple をつけるだけで、簡単にリッチ感漂う UI を実装できます 凄いです(*゚O゚)

css

  • ::ng-deep で padding 等を矯正しつつ、お好みのスタイルを当てます
%default-theme {
  color: #fff;
  background-color: #00897b;

  transition: all 0.3s ease-out;

  cursor: pointer;
  -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}

%disabled-theme {
  color: rgba(0, 0, 0, 0.5);
  background-color: rgba(0, 0, 0, 0.12);
}

.dropdown-button {
    position: relative;
    transform: translateY(-1px);
    transition: all 0.3s ease-out;

    &--disabled {
        box-shadow: none;
        transform: translateY(1px);

        .dropdown-button {
            &__main {
              @extend %disabled-theme;
            }

            &__trigger {
                @extend %disabled-theme;
            }
        }
    }

    &__main {
        @extend  %default-theme;

        & ::ng-deep .mat-button-toggle-label-content {
            font-size: 12px;
            font-weight: bold;
        }
    }

    &__trigger {
        @extend  %default-theme;

        & ::ng-deep .mat-button-toggle-label-content {
            padding: 0;
        }
    }
}

  • disable 時の translateY(1px) がこだわりポイント (・∀・)
  • 影が無くなるということは、物体はその分下に落ちる
  • ↑ をさり気なく行うことで ワンランク上のエフェクトになる気がしています
  • ホントは素直に 2px 移動させたいのですが、上下中央寄せされた際にずれが目立ってしまうので 1px と -1px にしました

ts

export interface DropdownButtonItem {
    type: string;
    text: string;

    icon?: string;
    isSelect?: boolean;
}
  • 自分が欲しい機能を考慮して 注入する選択要素の interface を定義
  • icon
    • メニュー側で表示する際に mat-icon を付ける
  • isSelect
    • 最初に選択されている要素(必要なら)

これをこんな感じで定義して

  selectedItems: DropdownButtonItem[] = [
    { icon: 'create', type: DropdownButtonItemTypes.Html, text: 'HTML' },
    { icon: 'save', type: DropdownButtonItemTypes.Css, text: 'CSS' },
    { icon: 'code', type: DropdownButtonItemTypes.Javascript, text: 'JS', isSelect: true }
  ];

作成した カスタムコンポーネント に渡します

  <app-dropdown-button [disabled]="disabled" [selectItems]="selectedItems" (confirm)="onConfirm($event)"></app-dropdown-button>
  • dropdown-button.component 自体はイベントの受け渡しをしているだけなので省略

完成!

angular-material2 の

  • mat-menu
  • mat-ripple
  • mat-button-toggle
  • mat-button-toggle-group

を組み合わせることで 簡単に 思い通りの DropdownButton を作成することができました (=゚▽゚)/

もし angular を使っていて DropdownButton が必要な方がいらっしゃいましたら チューニングしてお使いくださいm(__)m

5
4
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
5
4