1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

テンプレートエンジンにコンポーネントで抗う!!

Posted at

前書き

Reactは好き??
私は好きだしコンポをいろんなページにコンポとして
使い回せるからね。もうコピペはしたくない
でもjspやthymeleaf,jinja2じゃ使えないと思ってた。。
そんな事はないことが分かったのでその方法を記載します!!

前提知識

  • jsでDOM操作くらいならできる

唯一の代替手段、カスタムエレメンツ!!

なんとhtmlタグを自作する方法があったんですね!!
これを使うことで特定の構造に名前を付けたり
属性の変更を検知して中身を変更できたりします。
大半がイミュータブルに使うとは思いますが。
自作と言うとムズそうですがやることは簡単です。

test.js
class MyCompo extends HTMLElement{
    //DOMに追加時に呼び出される
    connectedCallback(){
        //シャドウルートの設定
        const shadow =this.shadowRoot.attach({mode:"close"});
        // 要素の作成 テストなのでdatasetをそのまま入れてますがホントはやめてね
        shadow.innerHTML = "<p>" + this.dataset.data + "</p>";
    }
}
custom.js
    document.customElements.define("my-compo",MyCompo);

コード解説

クラスの定義はjavaをやってれば分かるので飛ばします。
分からなくてもこんなもんだで良いですフロントエンド内で責務分離とかしないので

const shadow =this.shadowRoot.attach({mode:"close"});

ここは普通にjsやってると見慣れないですが、cssの適用範囲を狭めたり
コンソールからDOMやShadowRoot内jsの改変を出来なくする効果があります
結局取り出すときに改変される可能性があるのでスタイルやデータ取り出しのカプセル化位に思って置けば大丈夫です。

document.customElements.define("my-compo",MyCompo);

ここがカスタムエレメンツの肝です。
これを実行することでhtml内に普通に書いても動きますし
document.createElementでも作成できます!

なんか不便じゃない??

そうここでぶつかるのは、XSSのためにinnerHTMLの文は無くしたいけど
そうなったらjsでhtml作らなあかんやんという点です!
そこで紹介したいのはテンプレートタグです。

<template>
    <!-- pタグなど -->
</template>

上記のように定義できて効果は非表示と内部に入れたjsやcssのロード禁止です!
どれがどれって分かるようにタグ名-templateと未定義タグを入れても良いと思います。
使い方はほかのDOMと同じで要素を取得後、cloneしてテキストやイベントを差し込むだけです!!

querySelector().contents.cloneNode(true)

あとはjspにまとめて差し込んだり挿入をjsからするなら
ファクトリメソッドをいい感じに読ませるだけ!

ちなみにIEだと。。

もう無いと思いますがIEでの保守などクラス構文が使えない場合ですが
connectedCallbackの中身を書くだけなので再現はできます。
ただし、htmlからの直書きは出来なくなります。
また、関数もばらけてしまいます。。
そういう時は関数クロージャで実現可能です。

compo.js
function compo(){
    let list = null;
    
    const builder ={
        setList:function(inList){
            list =[];
            for(let index =0; index< inList.length;index++){
                list.push(inList[index]);
            }
            return this;
        }
        ,build(){
            //listを使った要素作成
            list[0];
            return root;
        }
    }
    Object.freeze(builder);
    return builder;
}

今回はBuilderパターンで描いてみましたが、
引数が少ない場合は直接でも良いです!
関数内部はさて置きあまり見ない部分を記載すると
関数トップレベルで変数を宣言し、返却するオブジェクト内で参照してますが、jsでは宣言したときに変数がreferenceErrorになってなかったら
その変数のアドレスを読みに行くのでなんとsetListもbuildもこのcompoメソッドの戻り値からなら動くんですよね🤣

さらにprivate変数と同じ効力を発揮するので代入をちゃんとコピーにしたりnullじゃなかったらエラーを出すようにすればイミュータブルにもなります!
buildインターフェースだけ持たせたオブジェクトをセットした後に返してセットを強制させることも可能です。
見づらくはなりますが意外とクラスより強力です。

Object.freezeはそのオブジェクトや配列を
read onlyにして書き込み禁止にできます。
メソッドでの上書きは禁止出来ないので、そこは注意ですね
tsがない環境での強力な選択肢です。

あとがき

htmlもjsも便利になったなと思いながらクロージャやObject.freezeは前から
出来たっぽいんですよね。。IEモードで対応してるのが証拠
多分イミュータブルやコンポ指向が最近の産物だから
活躍してないんだと思います。知らんけど!!

困ってた人はぜひ参考にしてください!!

参考

カスタム要素の使用
テンプレートタグ

1
0
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
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?