LoginSignup
8
6

More than 5 years have passed since last update.

javascript:カスタムイベントを使ったイベントハンドラの実装

Last updated at Posted at 2018-01-31

動機、やること

  • javascriptに(いつからか)CustomEventというユーザ定義のイベント発行機能が存在する(していた)ことを知った
  • オブジェクト間のメッセージング処理に使いたい
  • 恒例のIE独自仕様やイベントオブジェクトのdetailプロパティにカスタムデータを渡す仕様などは、僕の脳内の希少なワークスペースからご退出いただきたい
  • => CustomEventをラッパしたイベント処理を実装しよう!

開発環境

前提として環境は以下のような感じ。

  • npm
  • webpack3
  • babel
  • es6っぽく

実装(ライブラリ)

以下の実装全体をgithubにアップしました。差分がありましたらgithubを正とさせてください。。

イベント処理の実装本体はこんな感じ。

event.js
/**
 * 指定したkey名のカスタムイベントを送信する
 * @method send
 * @param  {string} key   カスタムイベント名
 * @param  {object} value データ
 */
export const dispatch = (key, value) => {
    let ev;
    try {
        ev = new CustomEvent(key, {detail: value});
    } catch(e) { // for IE
        ev = document.createEvent('CustomEvent');
        ev.initCustomEvent(key, false, false, value);
    }
    document.getElementsByTagName('body')[0].dispatchEvent(ev);
};

/**
 * カスタムイベントのリスナーを登録する
 * @method listen
 * @param  {string}   key      カスタムイベント名
 * @param  {Function} callback イベントリスナーから呼ばれる関数
 */
export const listen = (key, callback) => {
    document.getElementsByTagName('body')[0].addEventListener(key, callback);
};

今回はクラス間のイベント送受信が目的だったため、HTML上で確実に存在するbodyタグを固定で使用してイベント発行を行っています。

また、IEだけCustomEventコンストラクタが使えない独自仕様なので、IEの実装を吸収してあげます。
#こちら、出典サイトを忘れてしまったので(qiita内だったような)、ご存知の方は名乗り上げていただければ幸いです(他薦も可)。

実装(イベントリスナ側)

イベントリスナ側の実装は以下のような感じ。

listener.js
import { listen } from './event.js';
listen('app:ping', (e) => alert(`ping - ${e.detail}`));

実装(イベント発行側)

イベント発行側はこんな感じ。
ボタンのclickイベントでカスタムイベントを発行します。

dispatcher.js
import { dispatch } from './event.js';
document.getElementByTagName('button')[0].onclick = () =>  dispatch('app:ping', 'pong');

実装(その他)

ビルドのエントリポイントになるapp.jsを作成します

app.js
require('./listener.js');
require('./dispatcher.js');

ついでにwebpack.config.js

webpack.config.js
const path = require('path');
const webpack = require('webpack');

module.exports = {
    entry: {
        'app': './app.js'
    },
    output: {
        path: path.resolve(__dirname, "./"),
        filename: 'static/js/[name].js',
    },
    module: {
        rules: [
            {
                test: /\.js$/,
                exclude: [/node_modules/],
                use:[{
                    loader: "babel-loader",
                    options:{
                        presets:[
                            ['env', {'modules': false}]
                        ]
                    }
                }]
            },
        ]
    },
    devServer: {
        contentBase: path.resolve(__dirname, "./"),
        port:3000,
    },
    devtool: 'source-map',
};

package.jsonを適当に書いておきます。
npm initで生成し、依存関係を追加するなどしておいてください。
今回はbabelとwebpack、およびwebpack-dev-serverを使います。

package.json
{
    "name": "js-customevent",
    "version": "0.0.1",
    "description": "CustomEvent wrapper",
    "main": "index.js",
    "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1",
        "start": "node_modules/.bin/webpack-dev-server"
    },
    "author": "",
    "license": "ISC",
    "devDependencies": {
        "babel-core": "^6.26.0",
        "babel-loader": "^7.1.2",
        "babel-preset-env": "^1.6.1",
        "webpack": "^3.10.0",
        "webpack-dev-server": "^2.11.1"
    }
}

HTMLは最低限こんな感じ。

index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
</head>
<body>
    <button type="button">ボタン</button>
</body>
<script src="/static/js/app.js"></script>
</html>

上記ファイルをすべて同じフォルダに格納してください。

動作確認

上記準備が整った後で、ルートディレクトリ下で以下を実行します。

$ npm install
$ npm start

ブラウザから、http://localhost:3000/ にアクセスしてください。
ボタンを押して、以下のようなalertが表示したら動作確認完了です。

image.png

dispatch.js側で渡した「pong」というメッセージがlistener.jsで実行したイベントリスナに捕捉されて、alertに反映しました。

まとめ

javascriptのCustomEventを使ったイベントハンドリングについてご紹介しました。ご参考になれば幸いです。

こちらの現場からは以上です。

8
6
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
8
6