前回はなるべく素の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の多用は避けたい。。。ということで次のネタに続く…と。