1
3

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 3 years have passed since last update.

スマホでもhoverするボタンをtouchイベントを使ってシンプルに実装する

Posted at

概要

WebサイトやWebアプリを作っていて、「このボタン、スマホで動かすときは『タッチで色が変わって離したら戻る』みたいな感じにしたい…」と感じる人はちょいちょいいると思います。僕がそうです。

そのようなボタンをJavaScriptのtouchイベントを使ってシンプルに実装したので、サンプルを備忘録代わりにここに置いておきます。

サンプルはVueで作成していますが、Vueでなくてもやることは特に変わりません。
完成品を先に置いておくので、PCとモバイル端末でそれぞれ動きを確認してみてください。

完成品 : https://maple0922.github.io/vue-mobile-hover
Github : https://github.com/Maple0922/vue-mobile-hover

Touchイベントとは

Touchイベントは、PCのクリックではなくスマホやタブレット端末でのタッチ周りの操作に対して発生するイベントです。
これらを設定することで、モバイル独自のタッチ操作に対してイベントを発生させることができます。

こちらに詳しく書いてありますので詳細は割愛します。

【JavaScript】初心者でもわかるタッチイベント(touch event)

イベント 発生するタイミング
touchstart タッチ面に指が触れた時
touchend タッチしていた指を離した時
touchmove タッチしながら指を移動させた時
touchcancel なんらかの理由でタッチが取り消された時

サンプル

Vue CLIで作ったプロジェクトで、簡単なボタンとイベントを用意しました。

Main.vue
<template>
  <div class="container">
    <h1>Vue Mobile Hover</h1>
    <p>Hoverのみ</p>
    <button class="btn" @click="countUp">UP</button>
    <p>Touch Event実装</p>
    <button class="btn" @click="countDown">DOWN</button>
    <p>count: <input v-model="count" readonly></p>
  </div>
</template>

<script>
export default {
  name: "Main",

  data () {
    return {
      count: 0,
    }
  },

  methods: {
    countUp() {
      this.count++
    },
    countDown(){
      this.count--
    }
  }
};
</script>

<style lang="scss" scoped>
.btn {
  border: 1px solid blue;
  width: 200px;
  height: 50px;
  cursor: pointer;
  background: white;
  color: blue;
  &:hover {
    background: blue;
    color: white;
  }
  &:active {
    background: white;
    color: blue;
  }
}
</style>

ボタンをクリックしたらcountが上がったり下がったりするだけのシンプルなアプリです。
ボタンはhover時に背景色と文字色が入れ替わり、押下時に元に戻るようなcssを当てています。
マウスポインタがなぜか写ってくれませんが、UPのボタンにマウスをホバーさせています。

ここから、DOWNボタンのほうだけをモバイル端末でのhoverに対応させていきます。

ボタン実装

1.モバイル判定

まず、モバイルかPCかの判断をするためのisMobileというパッケージをインストールします。
メディアクエリでの判断ではクリック端末かタッチ端末かの判別ができないので不十分です。

$ npm i -D ismobilejs
Main.vue
<script>
+ import isMobile from "ismobilejs";

export default {
  name: "Main",

  data () {
    return {
      count: 0,
    }
  },
+
+  computed: {
+    mobile () {
+      return isMobile(window.navigator).any;
+    }
+  },

  methods: {
    countUp() {
      this.count++
    },
    countDown(){
      this.count--
    }
  },

};
</script>

mobileは取得したユーザーエージェントをisMobile.anyの判定にかけて、モバイル端末ならtrue,そうでないならfalseを返します。

2.pcのみにhoverイベントをつける

Main.vue
<template>
  <div class="container">
    <h1>Vue Mobile Hover</h1>
    <p>Hoverのみ</p>
-   <button class="btn" @click="countUp">UP</button>
+   <button class="btn" @click="countUp" :class="{ pc: !mobile}">UP</button>
    <p>Touch Event実装</p>
-   <button class="btn" @click="countDown">DOWN</button>
+   <button class="btn" @click="countDown" :class="{ pc: !mobile}">DOWN</button>
    <p>count: <input v-model="count" readonly></p>
  </div>
</template>

!mobile(モバイルでない)場合にpcというクラスを付けます。

Main.vue
<style lang="scss" scoped>
.btn {
  border: 1px solid blue;
  width: 200px;
  height: 50px;
  cursor: pointer;
  background: white;
  color: blue;
+ &.pc {
    &:hover {
      background: blue;
      color: white;
    }
    &:active {
      background: white;
      color: blue;
    }
+ }
}
</style>

hover,activeをpcの場合のみ適用します。
モバイル端末においてhoverやactiveのあてられている要素は挙動が少し変になるからです。

3.touchイベントの追加

Main.vue
<template>
  <div class="container">
    <h1>Vue Mobile Hover</h1>
    <p>Hoverのみ</p>
    <button class="btn" @click="countUp" :class="{ pc: !mobile}">UP</button>
    <p>Touch Event実装</p>
-   <button class="btn" @click="countDown" :class="{ pc: !mobile}">DOWN</button>
+   <button class="btn" @click="countDown" :class="{ pc: !mobile}" @touchstart="touchStart" @touchend="touchEnd">DOWN</button>
    <p>count: <input v-model="count" readonly></p>
  </div>
</template>

DOWNボタンに@touchstart@touchendイベントを追加し、それぞれtouchStart,touchEndメソッドを実行させます。

Main.vue
  // 省略
  methods: {
    countUp() {
      this.count++
    },
    countDown(){
      this.count--
    },
+   touchStart(e){
+     e.target.classList.add('touched');
+   },
+   touchEnd(e){
+     e.target.classList.remove('touched');
+   }
  },

タッチした要素に対し、に、@touchstart時にtouchedを付与、@touchend時にtouchedを削除するメソッドを定義します。
これで、ボタンに触れている間だけtouchedが付与されていることになります。

Main.vue
  // 省略
  &.pc {
    &:hover {
      background: blue;
      color: white;
    }
    &:active {
      background: white;
      color: blue;
    }
  }
+ &.touched {
+   background: blue;
+   color: white;
+ }
}

最後に、touchedに対してhover時と同じcssを適用します。
PCではtouchイベントは動かないので、Mobileだけに適用するといったことは必要ありません。

シンプルといいつつ少し長くなってしまいましたが、これでスマホでもいい感じに動くボタンが作れます。

完成品 : https://maple0922.github.io/vue-mobile-hover
Github : https://github.com/Maple0922/vue-mobile-hover

最後に

生のJavaScriptではaddEventListenerontouchstartなどを使って実装する形になりますが、基本的には『タッチしている要素にクラスを付与してCSSを適用させる』という部分は変わらないと思います。

あとボタンボタン言ってますが、むしろ見た目からは押せることがわかりにくい要素に対して「押せるよ!!」という意味で実装するのもいいかもしれません。

主にWeb制作をやっていて「なるべくJSは使わずCSSで済ませたい」という方もいると思います。近いうちに&:touchみたいな擬似クラスができてくれるといいですね。

1
3
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
1
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?