【JavaScript】カレンダーをtemplateタグでつくってみた

このたび **templateタグを使って** カレンダーを作成してみました。
「カレンダー作成　js」と検索してもあまり出てこないやり方ですが、いくつかのメリットがあったので紹介します。

## templateタグを使うメリット
templateタグには次のようなメリットがあります。

:::note 
js側でタグを文字列から生成せずに済む
:::
:::note 
同じ構造のHTMLを使い回せる
:::

💁‍♀️ < 詳しく説明します

### ① js側でタグを文字列から生成せずに済む

例えば、DOM要素をつくるためのコードを以下のように書くとします。

```js
let calendarHtml = document.querySelector('#calendarHtml'); // DOMを作成したい位置
calendarHtml.innerHTML = '<td>新しいDOM</td>';
```
このようにタグ記法の文字列を直接入力する場合、少しハードコーディング気味になってしまいます。また、条件を付け足したい時、文字列結合だとDOM操作ができないのでやや不便です。
templateタグを使うことで、HTMLからDOM要素を読み込み・操作できるため、これらの問題がクリアされます。


### ② 同じ構造のHTMLを使い回せる

同じ構造が何回か続く場合、一回分のtemplateだけを用意すれば使用する時にクローンして使い回せるので、記述するHTMLが最小限で済みます。


## 実際にカレンダーをつくってみた

<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="zYeapOa" data-user="uhhpnrer-the-flexboxer" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/uhhpnrer-the-flexboxer/pen/zYeapOa">
  カレンダー</a> by 山下茉莉花 (<a href="https://codepen.io/uhhpnrer-the-flexboxer">@uhhpnrer-the-flexboxer</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

### 条件
- 月初日より前の日付は何も記述しない
- 当日に印をつける
- 今日以降の日付をグレーアウトにする

### 用意したtemplateタグ

```calendar.html
<template id="oneWeek">
    <tr>
      <td></td>
      <td></td>
      <td></td>
      <td></td>
      <td></td>
      <td></td>
      <td></td>
    </tr>
</template>
```


### templateタグを使ったJavaScriptのコード

```calendar.js
const date = new Date();
const year = date.getFullYear();
const month = date.getMonth() + 1;

const calendarHeader = document.querySelector(".calendarHeader");
calendarHeader.textContent = `${year}年${month}月`;

// 月末日を取得
const totalDatesInMonth = new Date(year, month, 0).getDate();

const calendarHtml = document.querySelector("#calendar");
const tbody = document.querySelector("#tableBody");

// 日にちのカウント
let dayCount = 1;
const weekArray = [];
while (dayCount <= totalDatesInMonth) {
  const targetDate = new Date(year, month - 1, dayCount);
  // その月の第何週目かを取得
  const week = Math.floor((targetDate.getDate() - targetDate.getDay() + 12) / 7);
  // 'oneWeek'templateをクローンして作成
  const weekHtml = document.querySelector("#oneWeek");
  const weekTemplate = weekHtml.content.cloneNode(true);
  weekArray[week - 1] ||= weekTemplate;
  // 現在まわしている日付が第何週目の何曜日かを取得
  const targetCell = weekArray[week - 1].querySelector(`td:nth-of-type(${targetDate.getDay() + 1})`);
  // 日付をテキスト
  targetCell.textContent = `${dayCount}`;
  // targetCellが今日だった場合印をつける
  if (targetDate.toDateString() === date.toDateString())
  targetCell.classList.add("today");
  // targetCellが今日以降だった場合グレーアウトにする
  if (targetDate > date) targetCell.classList.add("disable");
  dayCount ++;
}

weekArray.forEach((week) => {
  tbody.appendChild(week);
});

```

## 感想
templateタグを使うことで、**js側でタグを文字列で生成せずに済み**, **何度も同じHTMLを記述する必要がなくなった**ため、シンプルで良いコードになった気がします。
カレンダー作成をしようと思っている人、ぜひ一度templateタグを使った方法を試してみてください！

## 参考記事
https://developer.mozilla.org/ja/docs/Web/HTML/Element/template

https://product.skyarc.co.jp/engineerblog/entry/customizewebpagelabel.html