[javascript]createElementとかaddEventListenerはダルい

createElementはダルい。

そもそも、innerHTMLを使えば済む。

createElementはタグ名が付いてるダケの空っぽなHTMLエレメントを作るだけなので

var button = createElement('button');
button.className = 'fileButton fileDrag';
button.id = 'fileButton' + buttonId;
button.type = 'button';
button.innerHTML = caption;
parentObj.appendChild(button);

と・・・ダラダラと書かないといけないから

      var fileButton  = createElement('button', {
        className:  ['fileButton','fileDrag'],
        id:         'fileButton' + buttonId,
        type:       'button',
        innerHTML:  caption,
        parent:     parentObj
      });

の様に連想配列でエレメントの属性を一式で指定できればいいのに・・・

と思ったので書いてみた。

    //  HTMLエレメントを作成します
    const createElement = (tagName, options) => {
      var eventList = ['ended'];
      var elm  = document.createElement(tagName);
      Object.keys(options).forEach( (key) => {
        // eventの場合
        if( eventList.includes(key) ) {
          elm.addEventListener(key,options[key]);
        } else {
          // event以外の場合
          switch(key) {
            case 'className': // プロパティはclassNameですが、タグの属性はclassなので別途に処理します。
              if(Array.isArray(options[key])) {
                elm.classList.add(...options[key]); // 配列を展開しパラメータとして引き渡す
              } else {
                elm.classList.add(options[key]);
              }
              break;
            case 'innerHTML': // setAttributeではタグ内にinnerhtml="***"と属性を生成するので別途に処理します。
              elm.innerHTML = options[key];
              break;
            case 'parent':    // setAttributeではタグ内にparent="***"と属性を生成する様で、画面に生成したエレメントを割り付けないので別途に処理します。
              options[key].appendChild(elm);
              break;
            default:
              elm.setAttribute(key, options[key]);
              break;
          }
        }
      });
      return elm;
    };

イベントに対応するeventListの中身が少ないのは、creapteElementの後で毎回addEventListenerするのも面倒なので、スクリプトの最初でクラス指定でイベント登録を済ませたかったから・・・

とは云え、クラス数×イベント数がいっぱいあったら、その分のdocument.addEventListenerは呼び出したくないので、

    const onLoadWindow = () => {
      //  コントロールのイベント処理を登録します
      const classEvents = [
        /* onload */
        { className:  'fileButton',         events:   { 'click':  onClickFileButton}},
      ...
      ];
      registEventListener(classEvents);
    };
    //  documenイベント処理
    var documentEvents = {};
    const documentEventListener = (event) => {
      // 処理
      var target = event.target || event.srcElement;
      Array.from(target.classList).map((className) => documentEvents[event.type][className])
        .filter((func) => func !== undefined)
        .forEach((func) => func(event));
    };
    //  指定クラスを持つHTMLエレメントにイベントを登録します
    const registEventListener = (classEvents) => {
      // classEvents配列数分ループ
      classEvents.forEach((classEvent) => {
        // イベント数分ループ
        Object.keys(classEvent.events).forEach((eventName) => {
          // クラスのイベントごとの処理
          if( documentEvents[eventName] === undefined ) {
            // documentEvents[eventName][classEvent.className]に代入できるように初期化
            documentEvents[eventName] = {};
            document.addEventListener(eventName, documentEventListener);
          }
          // ※同じクラス・同じイベントに対応する処理は1つだけ
          documentEvents[eventName][classEvent.className] = classEvent.events[eventName];
        });
      });
    };
    //  画面初期表示時の処理
    window.onload = onLoadWindow;

イベントごとに1回document.addEventListenerを呼び出し、イベント発生時に呼出された時にイベントターゲットのクラス名からイベントで処理したい関数をリストアップして呼び出す様にしてみた。

const classEvents =[
  {
    className:  'fileButton',
    events:   {
      'click':  onClickFileButton}
    },
  },
  ...
]

この書き方は思いついたイベントを書き殴るには都合がいいけど、documentEventsでは扱いにくいので

var documentEvents = [
  {
    'click': [
      {
        'fileButton': onClickFileButton,
        ...
      }
    ],
  ...
  }
]

に置き換え、documentEvents[‘click’][‘fileButton’]からonClickFileButtonが容易に取得できるようにしている。

で・・・全部済ませたかったが、

videoタグのendedイベントはdocument.addEventListenerで拾えなかったので

自作のcreateElementで作成したHTMLエレメントにaddEventListenerでendedイベントを登録できるようにした。(ワケ

気分的には楽になるけど、

なぜかソースは長くなる。(大笑い




コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA