テンプレートリテラルを使ってVanillaJSでもJSXライクな記述を
背景
令和の時代に生のHTMLを喜んでガリガリ書こうという人は少なくなってきているんじゃないでしょうか。
一方で、ちょこちょこっとしたUIだけのために、フレームワークを利用するのも億劫だったり、技術スタック的に難しかったりするケースもあると思います。
Vuejsなど、CDNで利用できるものは便利ですが、
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
Chrome拡張機能の開発には使えない[1]など、いつでも上手くいくわけではなさそうです。
そこで今回はVanillaJS(生のJS)で、ReactのようなJSX記法もどきを頑張って再現してみようと思います。
注意
今回の方法は、JavascriptでHTML文字列を生成する形になるので、直接HTMLを書く形式ではなく、insertAdjacentHtmlなどを用いて、生成した文字列をDOMの指定した場所に挿入するという形になります。
1. テンプレートリテラルを使う
ES6で登場したテンプレートリテラルは、${}
で囲うことで変数を直接書けることでよく知られていますが、改行がそのまま出力されるという性質もあります。
const str = '文字列';
const res = `${str}
です。`;
実行結果
改行が出力されていますね
使ってみる
これを利用することで長めのHTMLも可読性を損なわずに簡単にJSで扱うことができます。
// 長くなると見にくい
const htmlText = '<div class="container"><div class="wrapper"><div class="text sample">サンプル</div></div></div>';
// 文字列結合を使えば複数行で書けるがやや面倒
const htmlText = '<div class="container">' +
'<div class="wrapper">' +
'<div class="text sample">' +
'サンプル' +
'</div>' +
'</div>' +
'</div>';
// テンプレートリテラルを使う
const sampleClass = 'sample'; // 変数の埋め込みもわかりやすい
const htmlText = `<div class="container">
<div class="wrapper">
<div class="text ${sampleClass}">
サンプル
</div>
</div>
</div>`;
当然、コンポーネントもどきを作成することもできます。
const hoge = '<span>ほげほげ</span>';
const htmlText = `
<div>
${hoge}
</div>`
2. reduceを使う
配列展開もやりたいですよね。
Reactではmapメソッドを使いますが、今回はreduceを使って再現します。
Reactの場合
const FruitsList = () => {
const arr = [
{id: 'apple', value: 'りんご'},
{id: 'orange', value: 'みかん'},
{id: 'banana', value: 'バナナ'}
];
return (
<ul>
{arr.map(item => {
return <li key={item.id}>{item.value}</li>;
})}
</ul>
);
};
VanillaJSの場合
単一の値を返してくれるreduce関数を使うことで配列からHTML文字列を結合して出力します。
(mapとjoinでもできそうですね)
const arr = [
{id: 'apple', value: 'りんご'},
{id: 'orange', value: 'みかん'},
{id: 'banana', value: 'バナナ'}
];
const htmlText = `
<ul>
${arr.reduce((prev, item) => {
return prev + `<li id="${item.id}">${item.value}</li>`
}, '')}
</ul>`;
おわりに
ある程度の規模になってくると、ちゃんと開発環境を整えた方がいいですが、Chrome拡張機能や、GoogleAppsScriptでダイアログを表示するとか、ちょっとした利用には便利です。
-
manifest Version3からはunsafe-evalが許可されておらず、使えないようです。 ↩︎
Discussion