2018/04/23更新

[フロントエンド] React.jsで行のスワイプを実装する(Hammer.js利用)

このエントリーをはてなブックマークに追加      

こんにちは、@yoheiMuneです。
React.jsで、ネイティブのような行スワイプ処理を実装したので、ブログに残したいと思います。



目次




今回のサンプルコード

GithubのyoheiMune/react-hammer-drag-sampleに置いてあります。適宜ご参照ください。



何をしたいのか

以下のテーブルビューのようなUIの場合に、指でグググと動かして行をスワイプしたい。それをReact.jsで実現したいというお話です。
画像

デモはこちら




Hammer.jsについて

スマホ向けのWebページで、スワイプやピンチなどの指によるジェスチャーを扱いたい場合には、Hammer.jsが便利です。Angular.jsにも採用されていて、かなりの人気なライブラリです。
React.jsにおける指ジェスチャーもHammer.jsを使うと、お手軽に実装することができます。



npmインストール

React.jsでHammer.jsを扱うことができるライブラリはいくつかありますが、今回はreact-hammerjsを導入しました。採用理由としてはある程度Githubのスターも集まっているし、使い勝手も良さそうだったためです。

npm installで導入します。
$ npm install --save react-hammerjs



スワイプ処理を実装する

具体的な実装内容です。Cell.jsにスワイプ処理を実装し、それをApp.jsから利用する形で実装しました。


App.js

まず先に、Cell.jsの利用側です。特段考慮することはなく、普通のReact的な実装を行います。
import React, { Component } from 'react'
import Cell from './Cell'  // Cell.jsを読み込む
import './App.css'

class App extends Component {

  render() {
    return (
      <div>
        <h1>React.js and Hammer.js Sample.</h1>

        {/* スワイプできるCellを5つ並べてみる. */}
        <div className="items">
          {
            [1, 2, 3, 4, 5].map(num => {
              return <Cell num={num} key={num}/>
            })
          }
        </div>
      </div>
    )
  }
}

export default App
ここではCellを5つ並べてみました。


Cell.js

こちらがメインです。react-hammerjsを用いてスワイプ処理を実装します。
import React, { Component } from 'react'
import Hammer from 'react-hammerjs'   // Hammer.jsを使えるように読み込みます.
import './Cell.css'

// スワイプで開いたときの距離.
const SWIPED_DISTANCE = 150

class Cell extends Component {

  constructor() {
    super(...arguments)

    // 初期状態を定義します
    this.state = {
      // スワイプされた状態の場合にtrue.
      opened : false,
      // 指で動かしている時の移動距離.
      deltaX : 0
    }
  }

  // スワイプの開始位置を計算して返します.
  // open状態であれば-150pxがスタート地点、それ以外は0px.
  getFirstPosition() {
    return this.state.opened ? -1 * SWIPED_DISTANCE : 0
  }

  // 指でのドラッグが始まった時.
  onPanStart(e) {
    // 最初のCellの位置を設定します.
    this.setState({
      deltaX : this.getFirstPosition()
    })
  }

  // 指でドラッグしている.
  onPan(e) {
    // 指で動かした分だけ、移動距離を変化させます.
    this.setState({
      deltaX : this.getFirstPosition() + e.deltaX
    })
  }

  // ドラッグ終了
  onPanEnd(e) {
    // 移動量に応じて、openedの状態を変更します.

    // スワイプ前は開いていた場合
    if (this.state.opened) {
      // 75px(150pxの半分)の動きがあれば、閉じる.
      if (e.deltaX >= SWIPED_DISTANCE / 2) {
        this.setState({
          opened : false,
          deltaX : 0
        })
      // スワイプ量が少なければ、opened状態はそのまま.
      } else {
        this.setState({
          deltaX : this.getFirstPosition()
        })
      }
    
    // スワイプ前は閉じていた場合
    } else {
      // 75px(150pxの半分)の動きがあれば、開く.
      if (e.deltaX <= -1 * SWIPED_DISTANCE / 2) {
        this.setState({
          opened : true,
          deltaX : -1 * SWIPED_DISTANCE
        })       

      // スワイプ量が少なければ、opened状態はそのまま. 
      } else {
        this.setState({
          deltaX : 0
        })
      }
    }
  }

  render() {

    // スワイプ量に合わせて、要素の位置を変更する.
    let style = {
      transform : `translate(${this.state.deltaX}px, 0)`
    }

    // <Hammer>タグでスワイプのアクションを捕捉する.
    // onPanStart、onPan、onPanEnd、それぞれのイベントを扱います.
    // また、「style={style}」で移動距離を設定します.
    return (
      <Hammer
        onPanStart={this.onPanStart.bind(this)} 
        onPan={this.onPan.bind(this)} 
        onPanEnd={this.onPanEnd.bind(this)}>
          <div className="cell" style={style}>cell{this.props.num}</div>
      </Hammer>
    )
  }
}

export default Cell
少しコードが長いですが、onPanStartonPanonPanEndでスワイプを捉えて、その変化した量をCSSのtransform + translateで表現することで、スワイプアクションを実現しています。



最後に

Hammer.jsは色々なイベントを捕捉できるので、今回紹介したもの以外にも色々と実装できて面白いです。

最後になりますが本ブログでは、フロントエンド、サーバー、Swift、PHP、Node.js、Python、Java、Linux、インフラ、Go言語、機械学習、などの技術トピックを発信をしていきます。「プログラミングで困ったその時の、解決の糸口に!」そんな目標でブログを書き続けています。ぜひ、本ブログのRSSTwitterをフォローして貰えたら嬉しいです ^ ^

最後までご覧頂きましてありがとうございました!





こんな記事もいかがですか?

[取り組み] フロントエンドでコーディングスピードをアップさせる6つの方法!と思って書いてたら30個も書いちゃった。
[フロントエンド] フロントエンドの入社試験99問!難しいですよ〜w。
[フロントエンド] Webページを表示するテストの際に、通信速度を3Gに制限して表示してみよう
[フロントエンド] スマホ実機でのデバッグ手段を増やす!Macのプロキシを利用して、通信内容を確認する。
[フロントエンド] Chrome 35 Beta の変更点。Touch制御、新しいJavaScript機能、プレフィックスなしのShadowDOM
[フロントエンド]複数アカウントでのテストには、Chromeのユーザー管理を使って、Cookieを切り替えると便利
[フロントエンド] Chrome36βが出た。変更点など。element.animate、HTML Imports、Object.observe、他。
RSS画像

もしご興味をお持ち頂けましたら、ぜひRSSへの登録をお願い致します。