ストップウォッチを作ってみる[LWC]

概要

LWCでストップウォッチを作成します。
スタートの時間とストップの時間の差分を計算します。
ミリ秒単位で計測します。

ソースコード

stopwatchLwc.html

<template>
    <lightning-card>
        <div class="slds-grid slds-einstein-header slds-card__header">
            <header class="slds-media slds-media_center slds-has-flexi-truncate">
                <div class="slds-grid slds-grid_vertical-align-center slds-size_3-of-4 slds-medium-size_2-of-3">
                    <h1 class="slds-truncate" title="ストップウォッチLWC">
                        <span class="slds-text-heading_large">ストップウォッチLWC</span>
                    </h1>
                </div>
                <div class="slds-einstein-header__figure slds-size_1-of-4 slds-medium-size_1-of-3"></div>
            </header>
        </div>
        <div class="slds-align_absolute-center">
            <div class="slds-m-top_large">
            <header class="slds-col slds-size_1-of-1 slds-align_absolute-center" >
                <div class="curentTime slds-text-heading_large">00:00:000</div>
            </header>
            <main class="slds-align_absolute-center">
                <div class="slds-button-group slds-m-vertical_medium" role="group">
                    <lightning-button variant="neutral" label="スタート" onclick={startApp} class="slds-text-heading_medium slds-p-around_small" disabled={disableStartButton}></lightning-button>
                    <lightning-button variant="neutral" label="ストップ" onclick={startApp} class="slds-text-heading_medium slds-p-around_small" disabled={disableStopButton}></lightning-button>
                    <lightning-button variant="neutral" label="リセット" onclick={startApp} class="slds-button_text-destructive slds-text-heading_medium slds-p-around_small"></lightning-button>
                </div>
            </main>
            </div>
        </div>
    </lightning-card>
</template>

stopwatchLwc.js

import { LightningElement } from 'lwc';

export default class SimpleStopwatchLwc extends LightningElement {
    startButton = this.template.querySelector('#start');
    stopButton = this.template.querySelector('#stop');
    
    startTime; // 計測開始時刻
    timeToAdd = 0; // 経過時間
    measuringTime = 0; // 計測時間
    timerId; // clearTimeout用のID
    disableStartButton = false;
    disableStopButton = true;

    // 押されたボタンを判定する
    startApp(event) {
      let clickedButtonlabel = event.currentTarget.label;
      if(clickedButtonlabel === 'スタート') {
          // 計測開始 
          this.startTimmer();
      } else if(clickedButtonlabel === 'ストップ') {
          // 計測終了
          this.stopTimmer();
      } else {
          // 計測リセット
          this.resetTimmer();
      }
    }
        
    // 計測開始
    startTimmer() {
        this.disableStartButton = true;
        this.disableStopButton = false;
        this.startTime = Date.now();
        // 1秒毎に計測する
        this.countUp();
    }
    
    // 計測終了
    stopTimmer() {
        this.disableStartButton = false;
        this.disableStopButton = true;
        clearTimeout(this.timerId);
        this.timeToAdd += Date.now() - this.startTime; // 経過時間を記録
    }

    // 計測リセット
    resetTimmer() {
        this.disableStartButton = false;
        this.disableStopButton = true;
        clearTimeout(this.timerId);

        this.measuringTime = 0;
        this.timeToAdd = 0;

        // 計測時間を分に変換する
        this.convertTime();
    }
    
    // 計測時間を分に変換する
    convertTime(){
        let min = Math.floor(this.measuringTime / 60000); // 分
        let sec = Math.floor(this.measuringTime % 60000 / 1000); // 秒
        let ms = this.measuringTime % 1000; // ミリ秒

        // 桁数を固定
        min = ('0' + min).slice(-2); 
        sec = ('0' + sec).slice(-2);
        ms = ('00' + ms).slice(-3);

        const curentTimeText = this.template.querySelector('.curentTime');
        curentTimeText.textContent = min + ':' + sec + ':' + ms;
    }
    
    // 10ミリ秒毎に計測する
    countUp(){
        this.timerId = setTimeout(function(){
            this.measuringTime = Date.now() - this.startTime + this.timeToAdd;

            // 計測時間を分に変換する   
            this.convertTime();
            
            // 10ミリ秒毎に計測する
            this.countUp();
        }.bind(this),10);
    }
}

stopwatchLwc.js-meta.xml

<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>54.0</apiVersion>
    <isExposed>true</isExposed>
    <description>ストップウォッチLWC</description>
    <targets>
        <target>lightning__RecordPage</target>
        <target>lightning__AppPage</target>
        <target>lightning__HomePage</target>
    </targets>
</LightningComponentBundle>