<!DOCTYPE LNLY>

ノールック寿司グリップ🍣

Ripple (波紋) エフェクトのボタンをVue.jsで作る

ユーザが操作したことを視覚的に伝えるボタンを、Vue.jsを使ってコンポーネントとして作ります。

Ripple (波紋) エフェクト

クリックした箇所を中心に波紋が広がるようにかかるエフェクトです。マテリアルデザインで広く知られるようになりました。 マテリアルデザインガイドラインによれば、クリック箇所を特定せず、どこをクリックしても中心から広がるものは正確には Ripple エフェクトとは呼べないそうです。

コンポーネント化の恩恵

コンポーネント化することにより、複数の箇所で同じボタンを再利用できるわかりやすい利点の他に、ボタンを利用する側のコンポーネント上から、 Ripple エフェクトの実装を隠し、あたかもHTML標準の button 要素 かのように使うことができる利点があります。

Ripple エフェクトの実装は、シンプルな仕組みにしたとしてもそれなりにコード量があります。 クリック位置の特定や、 Ripple を表現するための要素、CSS Transition を含むボタン全体の CSS がそれです。 Vue.jsを使ってコンポーネントを分割することでこれらのコードを隠匿します。

Ripple エフェクトの再現

今回作成したRipple エフェクトは以下の手順で実現しました。

  1. button 要素のクリックした位置を取得・保持する
  2. Ripple を形成する span 要素 を挿入する
  3. 保持していたクリック位置を使って span 要素 の位置を変更する
  4. span 要素scale をゼロに変更する
  5. CSS Transition によって span 要素scaleopacity を変化させる
  6. Ripple を形成する span 要素 を削除する

Tips

今回ボタンを作成する過程で発見した点や気を使った点を記します。

type 属性について

button 要素の type 属性のデフォルト値は type="submit" ですが、経験上 type="button" で指定することがほとんどなので、 コンポーネント内で type="button" として初期値を変更しました。親要素からは特に指定せずとも、 type="button" として振舞います。

pointer-events プロパティについて

あまり使ったことがなかった CSS プロパティ pointer-events を使いました。このプロパティは値として none を指定することにより、その要素が補足するマウスイベントを無視するようになります。1 ボタンを高速で連打したとき、表示されている span 要素 がクリックを補足してしまい、 Ripple エフェクトの出現位置が意図しないところに変わってしまう問題を解消しました。 このプロパティは CSS Level 4 ですが、モダンブラウザは対応しており、 IEバージョン11から対応しています。

disable 属性について

Rippleエフェクト中にボタンを連続的にクリックできるかどうかは要件により異なると思われます。今回は、Ripple エフェクトが出ている間はボタンを非活性にして連打できないようにしました。

click イベントのハンドリングについて

今回作成したボタンはそれ単体では機能を持たず、単純に click イベントを vm.$emit するだけです。 click イベントはボタンを使うコンポーネント側で定義したハンドラを @click で補足して発火します。そのため、ボタンを再利用する箇所がどれだけ増えてもボタン側のコードを変更する必要がありません。

属性の上書きについて

ボタンを使う上で頻繁に制御すると思われる disabled 属性は、標準の button 要素に指定するのと同様に呼び出し側から制御できます。 今回作成したコンポーネントprops を受け取らないようになっていますが、標準で指定可能な属性はそのまま記述すれば上書きされます。 このため、先述した type 属性も、type="submit" として使用したい場合はそのように記述できます。