1. このページの目的
カスタムイベントを使ってみる。
2. 基本事項
イベントリスナーの登録
elem.addEventListener('awesome', function (e) { /* ... */ }, false);
      - この例の場合、ターゲットとなる要素に 
'awesome'という名前でイベントリスナーを登録している。 - 「この要素(elem)が 
'awesome'というイベントを持っている」わけではない。そうではなく、この要素に対してdispatchEvent()が実行される際に、指定されたイベント名でイベントリスナーが登録されていれば、それらが実行されるだけある。 
イベントの作成と発火
// イベントの作成
const eventAwesome = new CustomEvent(
  // イベント名
  'awesome',
  // オプション
  {
    bubbles: true, // バブリングを許可
    detail: { text: () => textarea.value } // データを保持させる
  }
);
// イベントの発火
elem.dispatchEvent(event);
      - この例の場合、ターゲットとなる要素に 
'awesome'という名前で紐付けられているイベントリスナーを実行させることになる。 - イベントリスナーが引数として受け取るのは、
dispatchEvent()に渡したイベントオブジェクトである。 - Eventクラスを使ってもよいが、CustomEventクラスならデータの保持などができる。Event を拡張したクラスは、これ以外にもたくさんあり、それぞれ独自に必要なメソッドなどが追加されている。
 - イベント名さえ同じにして「
new CustomeEvent()➡dispatchEvent()」すれば、何度でもその名前のイベントリスナーを実行させることができる。つまり、new CustomeEvent()で生成したたった1つのオブジェクトを、毎回dispatchEvent()に渡す必要はない。その都度イベントオブジェクト(イベント名は同じ)を作成して渡せば良い。 
3. デモ
HTML (本ページ内)
<!-- ここにカスタム要素を出力する -->
<input is="my-input1">
<script type="module">
// カスタム要素用クラスをインポートして、タグ名に紐付ける
import MyInput1 from './my-input1.js';
customElements.define('my-input1', MyInput1, {extends: 'input'});
const myInput1 = document.querySelector('input[is=my-input1]'),
      demo1Output = document.querySelector('#demo1-output');
myInput1.addEventListener('keydown', function(e) {
  demo1Output.textContent = '';
});
// カスタムイベントにリスナーを登録する
myInput1.addEventListener('b-input', function(e) {
  demo1Output.textContent = `"b" が入力されました!(${e.detail})`;
});
</script>
      JavaScript (my-input1.js)
export default class extends HTMLInputElement {
  constructor() {
    super();
    this._onInput = this._onInput.bind(this);
    this.addEventListener('input', this._onInput);
    // カスタムイベントリスナーを登録する
    this._onBInput = this._onBInput.bind(this);
    this.addEventListener('b-input', this._onBInput, false);
  }
  disconnectedCallback() {
    this.removeEventListerm('b-input', this._onBInput);
  }
  _onInput(e) {
    const c = e.data;
    if (c == 'b') {
      // イベントを作成
      const event = new CustomEvent('b-input', {
        bubbles: true,
        detail: 'イベントに保持された値' // object をセットすることも可能
      });
      // イベント発火!
      this.dispatchEvent(event);
    }
  }
  _onBInput(e) {
    console.log(e);
  }
};
      実行結果
以下の <input> 要素には、'b' が入力されたときだけ発火するイベントが設定してある。
4. メモ
- 1つのイベントに対する複数のリスナーの実行順序は指定できないっぽい。