続:ES6とDOMの件

前回はなるべく素のjavascriptでDOMっぽい構文を考えてみようということで、下記のような即時関数を使用して子要素を生成して内容を定義しつつ親要素にアペンドするような形で、文書構造に則したコーディングが出来るのではないかという感じで投稿しました。

((body) => {                            // bodyを引数とした矢印関数①
  body.className='hogehoge';
  body.innerHTML = '';
  body.appendChild(((title) => {        // bodyタグへのappendChildを同様に矢印関数で記述②
    title.innerHtml = "page title";
    return title;
  })(document.createElement('h1')));
  body.appendChild(((content) => {      // 同様に本文ダグも矢印関数で生成と同時にappendChild
    content.innerHtml = "page content";
    return content;
  })(document.createElement('p')));
  return body;                          // ①関数の戻り値(これが無いと結果が空になる)
})(document.querySelector('body'))      // ①関数の引数として body = document.querySelector('body')

結果↓

<body>
<!--
   空のHTML文書
-->
</body>

=>

<body class="hogehoge">
  <h1>page title</h1>
  <p>page content</p>
</body>

慣れてしまえばサクサク書けてしまうが、やっぱり文書構造が大きくなると即時関数の入れ子だらけになって見にくくなってくるのと、即時関数のretrun文を入れ忘れて文書が真っ白になりがちという欠点も見えてくる。

というか、そもそもappendChildなどのメソッドが自身を返してくれればメソッドチェインでもっと便利に使えるのに・・・ということで、あまり大規模にならない程度に下記の拡張メソッドをHTMLElementに追加してみた。

/**
 * ① 自身を引数とする関数を引数に取り、処理を行った後、自身を返す
 */
HTMLElement.prototype.editElement = function(func) {
  func(this);
  return this;
}

/**
 * ② appendChild(文字列引数の場合はappend)処理を行った後、自身を返す
 */
HTMLElement.prototype.appendChain = function(child) {
  if(child instanceof HTMLElement){
    this.appendChild(child);
  } else if (typeof(child) === "string") {
    this.append(child);
  }
  return this;
}

/**
 * ③ 子要素をクリアしたのち自身を返す
 */
HTMLElement.prototype.clearElement = function() {
  this.innerHTML = "";
  return this;
}

これらを定義することで、先の構文は下記の様に書き換えられる(思った以上にスッキリ)

document.querySelector("body")
  .clearElement()
  .editElement(body => body.className = "hogehoge")
  .appendChain(document.createElement("h1").appendChain("page title"))
  .appendChain(document.createElement("p").appendChain("page content"));

良い感じになってきたー。と思ったけど、良く考えたら最近Web製作に関してはTypescriptに移行しつつあり、こんな型の曖昧な仕様を実装するのとても面倒な気がする・・・かといってanyの多用は避けたい。。。ということで次のネタに続く…と。

EC6とDOMの件

EcmaScript6(javascript)の勉強の件で、DOMの記載に関して考えてみた。以前のjavascriptではjQueryなどのライブラリを使ってDOMを簡潔に記載していたが、EC6以降も豊富なライブラリを使う機会が増えているような感じ。

しかし、折角なので、ここはライブラリを使用せずに素のEC6でDOMを分かりやすく記述出来ないものかと考えてみた。通常、素のjavascriptでDOMを記載するときは、例えばBODYタグから下を全てDOMで記述する場合

const body = document.querySelector("body"); // まずBODYタグを見つける
var title = document.createElement("h1");    // タイトル用のH1タグを生成
title.innerHtml = "page title";              // タイトル文字を設定
body.appendChild(title);                     // タイトルをBODYの子要素とする
var content = document.createElement("p");   // 本文段落用タグを生成
content.innerHTML = "page content";          // 本文を設定
body.appendChild(content);                   // 本文をBODYの子要素とする

の様に、既存のタグを見つけるか、新規タグを生成して内容を設定し、親要素に接続する作業を繰り返して文書構造を組み立てていく形になるが、階層が深くなると何が何だか分からなくなってしまう。そのあたりをjQueryでは文書構造に沿った形で記述出来て便利なのだが、”$”関数の数珠つなぎとなりなんだか違う言語のような気がして、個人的には好きにはなれなかった。そこでEC6ではライブラリを一切用いずに次のように記載してみた。

((body) => {                            // bodyを引数とした矢印関数①
  body.className='hogehoge';
  body.appendChild(((title) => {        // bodyタグへのappendChildを同様に矢印関数で記述②
    title.innerHtml = "page title";
    return title;
  })(document.createElement('h1')));
  body.appendChild(((content) => {      // 同様に本文ダグも矢印関数で生成と同時にappendChild
    content.innerHtml = "page content";
    return content;
  })(document.createElement('p')));
  return body;                          // ①関数の戻り値(これが無いと結果が空になる)
})(document.querySelector('body'))      // ①関数の引数として body = document.querySelector('body')

同様の内容を文書構造を意識した記載方法にしてみた。矢印関数を用いてタグを生成(またはquery)し、タグの内容を関数内で記載。子要素も矢印関数内で新たに矢印関数で生成したタグをその場でappendChildする。

かなり冗長な記述になるが、文書構造がHTMLに近い形で多少は見やすくなるのではと考える。

というか、そもそも文書全体をDOM化しようとするからイケないんですけどねw
あと、Lispかっ?!てくらい括弧がメチャメチャ多くなるので、エディタの力を借りないと括弧が一個違うとかでバグ探しも大変なことになりそう。。。vscodeさんありがとう!

IEさようなら

こちらのブログはwordpressを使っているので、まだ大丈夫っぽいですが、ポータルサイトは先月辺りにBootstrap5にアップグレードしたのでいよいよIEでは見られないサイトとなってきました。具体的にBotostrap5のどこがIEでダメなのかはよく調べてないですが、とりあえずjavascriptの記述はmodule式にしたのでIEでは動作はしません。

bootstrap5からjavascriptの形式としてesm(EcmaScriptModule?)が追加されているので、これはモジュールとして使用する必要があります。この場合従来では

<head>
    ・・・・・
    <meta charset="UTF-8">
    <link rel="stylesheet" href="css/bootstrap.css">
    <script type="text/javascript" src="js/bootstrap.bundle.js"></script>
    ・・・・・
</head>

上記のようにヘッダで設定していたものを

<head>
  ・・・・
  <style type="text/css">
    @import '/css/bootstrap.css';
  </style>
  <script type="module">
      import { Alert, Button, Carousel, Collapse, Dropdown, Modal, Offcanvas, Popover, ScrollSpy, Tab, Toast, Tooltip } from "./js/bootstrap.esm.js";
  </script>
  ・・・・
</head>

と、新しい形で書いてあげる必要があります。

まぁ、esmじゃ無い方を使えば従来式で書けるんだけど、まぁ新しいモノ好きということで。。。