小原 達也/ 2024年 1月 15日/ 技術

こんにちは!小原です。

ユーザーに処理結果を伝える方法として、alert() 関数を使う方法があります。
たしかに手軽に必要な情報を伝える方法ではあるのですが、ユーザー側からするとポップアップを閉じる手間が発生します。

そのため、より手間をかけない配慮をすることが好ましいです。

解決策として、一時的にコメントを表示させて数秒後に隠すという方法もあります。
いわゆるトーストメッセージと呼ばれるものです。

今回は、数秒間だけ表示させるシンプルなトーストメッセージのようなものを作成してみます。

本記事の内容は、サスケWorksのPremiumプランにご加入の方にお試しいただけます。
JavaScript, HTML/CSS の基本的な知識があれば、ほぼコピペで実装できるように構成しました。

完成イメージ

今回は以下のようなトーストメッセージを表示させてみます。

上記はサンプルとして、ページが読み込まれたときに表示されるようにしました。

JavaScriptを追加することで、トーストメッセージが表示されるタイミングを制御することもできます。

まずは上記でご紹介させていただいた、ページ読み込み時に表示させる方法から解説します。

実装の流れ

ページ読み込み時にトーストを表示させるだけであれば、以下の流れで実装可能です。

  1. JavaScriptコードの追加
  2. CSSスタイルの追加
  3. 動作確認

JavaScriptコードの追加

まずはアプリの右上のスパナマークをクリックします。

サイドバーから「カスタムコード」を選択します。

右上の「新規登録」ボタンをクリックして、設定画面に進みます。

すると、「カスタムコードの基本設定」という画面が表示されます。
以下を参考に、設定を行ってください。

  • 状態: 公開
  • 名称: JS:トーストメッセージ
  • 適用画面: レコード一登録画面
  • コード種別: JavaScript

入力が終わったら「保存」ボタンをクリックして設定を終了します。

次に以下の画面に遷移するので、「ソースコードの入力」をクリックして先に進みましょう。

続いてコードエディタが表示されます。
まずは、すでに書かれているコードを削除してまっさらな状態にします。

そのうえで、以下のコードを貼り付けます。

// トーストを表示するHTMLタグをBodyタグ内に追加する
function addToastHtmlTag(toastHeadline, toastMessage) {
    const htmlString = `
        <div class="toast-header">
            <strong>${toastHeadline}</strong>
            <button type="button" class="toast-close">
                <span aria-hidden="true">×</span>
            </button>
        </div>
        <div>
            ${toastMessage}
        </div>
    `
    // トーストを格納するdivタグを生成
    const toastDiv = document.createElement('div');
    toastDiv.id = 'toast';
    toastDiv.className = 'toast';
    toastDiv.innerHTML = htmlString;

    // body要素に追加する
    document.body.appendChild(toastDiv);

    // 設置したトーストを取得
    const closeBtn = toastDiv.querySelector('.toast-close');

    // 閉じるボタンでトーストを閉じる
    closeBtn.addEventListener('click', () => {
        toastDiv.style.visibility = 'hidden';
    });
}

// トーストを表示する
function showToast() {
    const toastElement = document.querySelector('#toast')
    toastElement.classList.add('toastFadeIn');
    toastElement.style.visibility = 'visible';
    // 3秒後に自動的に閉じる
    setTimeout(function () {
        toastElement.style.visibility = 'hidden';
        toastElement.classList.remove('toastFadeIn')
    }, 3000);
}

// 変数定義
const toastHeadline = 'タイトル';
const toastMessage = 'メッセージ';

window.addEventListener('DOMContentLoaded', () => {
    addToastHtmlTag(toastHeadline, toastMessage);
    showToast();
});

なお、以下の箇所はお好きな文字列に置き換えてください。

// 変数定義
const toastHeadline = 'タイトル部分の文字列';
const toastMessage = 'メッセージ部分の文字列';

対応関係は次のようになっています。

なお、文字列は'(クオテーションマーク)で囲うことにご注意ください。

クオテーションマークなしだと、JavaScript上で値の扱いが変わってしまうためです。

CSSスタイルの追加

CSSを書く場所を用意します。
大きくはJavaScriptの追加と同様ですが、一部手順が異なるのでご説明します。

先ほどと同様、アプリの右上のスパナマークをクリックします。

サイドバーから「カスタムコード」を選択します。

右上の「新規登録」ボタンをクリックして、設定画面に進みます。

「カスタムコードの基本設定」という画面が表示されます。
ここでコード種別を「CSS」としてください。

  • 状態: 公開
  • 名称: CSS:トーストメッセージ
  • 適用画面: レコード一登録画面
  • コード種別: CSS

入力が終わったら「保存」ボタンをクリックして設定を終了します。

次に以下の画面に遷移するので、「ソースコードの入力」をクリックして先に進みましょう。

続いてコードエディタが表示されます。
まずは、すでに書かれているコードを削除してまっさらな状態にします。

そのうえで、以下のコードを貼り付けます。

@keyframes fadeIn {
    0% {
        opacity: 0;
    }
    /* 少し早めに透明度を下げておく */
    20% {
        opacity: 0.5;
    }
    100% {
        opacity: 1;
    }
}

.toastFadeIn {
    animation: fadeIn 1s ease;
}

.toast {
     /* デフォルトは隠す、クリックで表示 */
    visibility: hidden;
    max-width: 350px;
    width: 100%;
    background-color: #fff;
    position: fixed;
    top: 1em;
    right: 1em;
    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
    border: 1px solid #999;
    border-radius: 5px;
    padding: 20px;
    z-index: 10000;
}

.toast-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
}

.toast-close {
    border: none;
    background: none;
    font-size: 1.6rem;
}

以上でトーストを表示させるための設定は完了です。

動作確認

続いて実際に動作を確認します。
今回「カスタムコードの基本設定」の「適用画面」として「レコード登録画面」を設定しました。
そのため、アプリの「レコード登録」というタブをクリックすれば、ページが表示されるときにトーストが表示されるはずです。

このような表示がされていれば、成功です。

ページ表示時以外にトーストを表示させる方法

先ほどのコードは説明の便宜上、「レコード登録画面」が表示された直後にトーストを表示させました。

ところが実際には、なにかユーザー側のアクションなどに応じる形でトーストを表示させたい場合がほとんどだと思います。

そこで、ここからは特定のテキストボックスがクリックされたときにトーストを表示させる方法をご紹介します。
先ほど追加したJavaScriptコードを一部改変することで実現していきましょう。

JavaScriptコードを一部改変

「JS:トーストメッセージ」という名前で保存したJavaScriptコードを改変します。

今回の場合、変更後のコードは以下となります。

/*!
 * SaaskeSDK
 * Copyright (c) North Torch Co.,ltd. 2023
 * Released under the MIT License.
 * ライセンスの全文は以下をご参照ください
 * LICENSE: https://github.com/northtorch/saaske-sdk/blob/main/LICENSE.md
 * README: https://github.com/northtorch/saaske-sdk/blob/main/readme.md
*/
// ↓↓↓ 以下追加したコード ↓↓↓
function getElementsByDisplayText(baseList = []) {
    // 引数で受け取った要素が配列かどうかを確認
    if (!Array.isArray(baseList)) {
        throw new Error('引数は配列である必要があります');
    };

    // すべてのdlタグを取得
    const dlTags = document.getElementsByTagName('dl');
    // 結果を格納する配列
    let targetElements = [];

    // すべてのdlタグをループ
    Array.from(dlTags).forEach(dlTag => {
        // レコード項目名部分を取得
        const dtTag = dlTag.getElementsByTagName('dt')[0]
        const dtText = dtTag.textContent.trim()
        // テキストボックス等を取得
        const ddTag = dlTag.getElementsByTagName('dd')[0]

        if (baseList.length == 0) {
            // 取得対象が無指定なら全取得
            targetElements.push(ddTag);
        } else {
            // 取得対象の指定ありなら取得対象リストに合致しているもののみ取得
            if (dtText.includes(baseList)) {
                targetElements.push(ddTag);
            };
        };
    });
    return targetElements;
};

function getDetailElms(targetElement) {
    // 取得するHTMLタグとtypeを選択
    const targetTagAndType = `
    input[type="text"], input[type="password"], input[type="email"], input[type="tel"],
    input[type="url"], input[type="number"], input[type="checkbox"], input[type="radio"],
    textarea, select, #tag_group, a
    `

    // 取得対象となるHTMLタグをすべて取得
    const target = targetElement.querySelectorAll(targetTagAndType)
    if (target.length == 0) {
        // 該当なしならnullを返す
        return null;
    } else {
        // 該当ありなら取得したNodeListを返す
        return target;
    };
};

function getTextFromSelection(selectTagElm) {
    // select2 の元となる要素のidを取得
    const targetId = selectTagElm.id

    // テキスト部分を抽出
    const $originalSelect = $(`#${targetId}`);
    const selectedText = $originalSelect.find('option:selected').text();
    return selectedText;
}
// ↑↑↑ ここまで追加したコード ↑↑↑

// トーストを表示するHTMLタグをBodyタグ内に追加する
function addToastHtmlTag(toastHeadline, toastMessage) {
    const htmlString = `
        <div class="toast-header">
            <strong>${toastHeadline}</strong>
            <button type="button" class="toast-close">
                <span aria-hidden="true">×</span>
            </button>
        </div>
        <div>
            ${toastMessage}
        </div>
    `
    // トーストを格納するdivタグを生成
    const toastDiv = document.createElement('div');
    toastDiv.id = 'toast';
    toastDiv.className = 'toast';
    toastDiv.innerHTML = htmlString;
    // body要素に追加する
    document.body.appendChild(toastDiv);
    // 設置したトーストを取得
    const closeBtn = toastDiv.querySelector('.toast-close');
    // 閉じるボタンでトーストを閉じる
    closeBtn.addEventListener('click', () => {
        toastDiv.style.visibility = 'hidden';
    });
    addClickEvent();
}
// トーストを表示する
function showToast() {
    const toastElement = document.querySelector('#toast')
    toastElement.classList.add('toastFadeIn');
    toastElement.style.visibility = 'visible';
    // 3秒後に自動的に閉じる
    setTimeout(function () {
        toastElement.style.visibility = 'hidden';
        toastElement.classList.remove('toastFadeIn')
    }, 3000);
}

// 変数定義
const toastHeadline = 'タイトル';
const toastMessage = 'メッセージ';
window.addEventListener('DOMContentLoaded', () => {
    addToastHtmlTag(toastHeadline, toastMessage);
    // 削除したコード
    // showToast();
});
window.addEventListener('load', () => {
    // 追加したコード
    const oneLinerTextBox = getElementsByDisplayText(['一行テキスト'])[0]
    oneLinerTextBox.addEventListener('click', () => {
        showToast();
    });
});

どのテキストボックスを取得するかは、以下の部分で指定しています。

const oneLinerTextBox = getElementsByDisplayText(['一行テキスト'])[0]

今回は「一行テキスト」という項目名のついたテキストボックスを指定したため、このような表記になっています。
例えば「住所」という項目名のものにしたい場合は、以下のように書き換えます。

const oneLinerTextBox = getElementsByDisplayText(['住所'])[0]

動作確認

テキストボックスをクリックしてトーストが表示されれば、正常な動作になります。

今回の記事は以上になります!
お疲れさまでした。

補足

「テキストボックスのクリック」以外に反応する仕組みを構築するには、もうひと手間必要になります。
一つ目はChromeなどのブラウザの開発者ツールを使って、HTMLタグを特定する作業。
二つ目はそれらの情報を使ってJavaScriptコードを構築する作業になります。

今回の記事では少々難易度が上がってしまうので割愛しますが、興味のある方はぜひご自身で試してみてください。
「DOM操作」、「HTML要素取得」などがキーワードになってくると思います。

ソースコード公開中

本記事で紹介したコードは、GitHubからもご覧いただけます。

https://github.com/northtorch/saaske-sdk/tree/main/toastMessage

サスケWorks関連記事はこちら

本ブログでは、サスケWorksのカスタマイズ系記事も順次アップ予定です。

>> NorthTorch - サスケWorks 関連記事

ぜひ、別記事の方もご覧ください。