【JavaScript】指定した日時になると自動で告知表示したい

### 制作経緯
とあるwebサイトで毎月購読者プレゼント企画を行っているのですが、筆者が案件に関わる以前より長らく**期限が来れば手動でプレゼントフォームを閉じるというアナログ作業**が行われていました。
（※ここで言うフォームを閉じるとは、期限切れと次月応募開始日を明記した別途HTMLページに差し替える作業になります）
当然、手動なので作業漏れが起きますし、何より差し替え作業を毎月意識しておく必要があるためストレスでした。

そこでJavaScriptを用いて指定した日時に自動でフォームを閉じる機能を実装しました。
これ以降、作業漏れはもちろん無くなりましたし、作業負担のストレスも軽減されました。
### ひとまず完成品
<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="abYrbQR" data-user="benjuwan" 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/benjuwan/pen/abYrbQR">
  limitTimer</a> by benjuwan (<a href="https://codepen.io/benjuwan">@benjuwan</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

次項から具体的な記述を説明していきます。

### HTMLの記述
```
<body>
  <div class="globalWrapper">
    <section>
      <div class="content"></div>
    </section>
  </div>
</body>
```
別段、特別な記述はありません。

### CSSの記述
以下記述（SCSS）では、不要だと思われる装飾意図の部分を省いて載せています。
※ CSS での記述も念のため記載しています。
```
body{
　// .closed がクローズ機能に関わるスタイル部分
  & .closed{
    position: fixed;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 100%;
    height: 100%;
    display: grid;
    place-items: center;
  
　　// 子要素は自由に設定してください
    & p{
      font-size: 14px;
      width: clamp(160px, calc(100vw/2), 560px);
      line-height: 2.2;
      text-align: center;
      padding: 4em 0.5em;
    }
  }
}
```
<details>
<summary>CSS ver</summary>

```
// .closed がクローズ機能に関わるスタイル部分
body .closed {
    position: fixed;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 100%;
    height: 100%;
    display: grid;
    place-items: center;
  }

// 子要素は自由に設定してください
body .closed p{
      font-size: 14px;
      width: clamp(160px, calc(100vw/2), 560px);
      line-height: 2.2;
      text-align: center;
      padding: 4em 0.5em;
    }
```
</details>

### JavaScriptの記述
関数で作っても良かったのですが、習熟度向上を目指してクラスで制作しました。
```
class PresentCloseSys {
  constructor(targetYear, targetMonth, targetDate, targetHours, targetMinutes, targetFunction){
	this.targetYear = targetYear;
	this.targetMonth = targetMonth;
    this.targetDate = targetDate;
    this.targetHours = targetHours;
    this.targetMinutes = targetMinutes;
    this.targetFunction = targetFunction;

    const timer = setInterval(()=>{
      let now = new Date();
	　let getYear = now.getFullYear();
      let getMonth = now.getMonth()+1;
      let getDays = now.getDate();
      let getHours = now.getHours();
      let getMinutes = now.getMinutes();

      /**
       * デフォルトでは「00が省略（=表示されない）されてしまう」ので（年以外の）桁数を揃える指定を行う
       * String(対象の要素).padStart(2,'0') // 対象の要素を文字列に変換して「必ず2桁数になるよう0で揃える・埋める(=00)」
       */
      let NowDateStr = `${getYear}${String(getMonth).padStart(2,'0')}${String(getDays).padStart(2,'0')}${String(getHours).padStart(2,'0')}${String(getMinutes).padStart(2,'0')}`;
      let targetTimeStr = `${this.targetYear}${String(this.targetMonth).padStart(2,'0')}${String(this.targetDate).padStart(2,'0')}${String(this.targetHours).padStart(2,'0')}${String(this.targetMinutes).padStart(2,'0')}`;

        //（数値の大小で条件分岐させるために）型をstrからintに変換
        let NowDate = Number(NowDateStr);
        this.targetTime = Number(targetTimeStr);
			
        if(NowDate >= this.targetTime){
          clearInterval(timer);
          // 指定時間の到達後に処理させたい内容（関数）の指定
          this.targetFunction();
        }
    }, 1000);
  }
}
```
1秒ごとに現在日時（の数値）`NowDate`をカウントしていき指定時間`this.targetTime`を超えたら指定した処理`this.targetFunction()`を行う設定です。

記述したクラスの使用例が以下となります。
```
　// アナウンステキスト
　const nextModifyInfo = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.<br /> Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.';

  // 処理させたい内容（関数：this.targetFunction(); に該当）
  function targetFunction_Ver001(){
    const targetEl = document.body;
    if(nextModifyInfo === ''){ // アナウンステキストに記入なしの場合
      targetEl.classList.toggle('NoTxt_toggleClass');
    } else {
      targetEl.classList.toggle('NoTxt_toggleClass');
      targetEl.insertAdjacentHTML('beforeend', `<div class="closed"><p>${nextModifyInfo}</p></div>`);
    }
  }
	
  // （左から）年,月,日,時,分,アナウンステキスト,関数を指定
  new PresentCloseSys(2023, 8, 10, 19, 15, targetFunction_Ver001);
```

コード内にあるように、
```
new PresentCloseSys(2023, 8, 10, 19, 15, targetFunction_Ver001);
```
の部分で、年、月、日、時、分、アナウンステキスト、関数を指定しています。
上記だと「2023年8月10日の19時15分」になります。

### 使用用途と注意事項
使用用途としては、筆者のようにフォームの自動クローズ機能のほか、
- イベントの開催告知（開始時間になるとイベントページへのリンクを表示する）
- 複数サイトで同じ案内を同時刻に行う必要がある場合
- 告知用途ではなく指定時間に別途デザインを切り替える
- 告知用途ではなく指定時間に一部のテキストや要素を変更する
- カウントダウン（クラス内の記述で「指定時間`this.targetTime` - 現在時間`NowDate`」の結果を返して表示するような調整が必要）
などがあるかなと思っています。

注意事項としては、CSSでスタイルを当てているだけなので処理実行後に開発者ツールで`display: none`とか、当該箇所のスタイルを変更されたら機能が無効化されます。

### さいごに
CodePen で、他にもスライダー機能やスクロールに応じた画像表示機能、ライトボックス機能なども書いているので良ければ見てやってください。
ここまで読んでいただきありがとうございました！

https://codepen.io/benjuwan