1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ぷよクエをたのしく!アプリをつくってみよう!(UI操作編:MessageBox)

1
Last updated at Posted at 2026-05-21

メッセージボックスをつくってみる

アプリを作っていると必要になってくるのは「処理を確認するための問い合わせ」だと思う。
いわゆる「メッセージボックス」を表示するための要素を考えてみた。

UIイメージ

こんな感じのUIがあれば、とりあえずはアプリで使えそう。

■「OK」タイプ
チェックボックス付.png

■「YES・NO」タイプ
MsgBoxYesNo.png

■「ABOUT」タイプ
MsgBoxOK.png

■「認証」タイプ
認証メッセージボックス.png

HTML での表現

各タイプのメッセージボックスを表示するためのHTMLを表現すると、こんな感じになった。
※最も単純なイメージです。

<!-- メッセージボックスの本体 -->
<div id="evona-msg-box">
  <!-- メッセージボックスを覆う背景 -->
  <div class="msg-overlay">
    <!-- メッセージボックスの表示内容 -->
    <div class="msg-panel">
      <!-- ヘッダー -->
      <div class="msg-header">[ヘッダー内容]</div>
      <!-- メッセージ内容 -->
      <div class="msg-body">[メッセージ内容]</div>
      <!-- フッター -->
      <div class="msg-footer">
        <button id="evona-msg-box-b1">OK</button>
      </div>
    </div>
  </div>
</div>
タグ 用途
メッセージボックスの本体 メッセージボックスの全体を構成する
メッセージボックスを覆う背景 メッセージボックスを表示している間に他の表示要素を操作できないようにするための「バリア」
メッセージボックスの表示内容 ヘッダー・メッセージ内容・フッターの親要素
ヘッダー いわゆるヘッダー
メッセージ内容 表示内容を表すHTML
フッター いわゆるフッター

UIの実装は、今までに作成したUIの実装経験で、こんな感じになった。

HTMLをDOMへ追加

export const MessageBoxButtonTypes = {
    None: "None",
    Ok: "Ok",
    OkCancel: "OkCancel",
    YesNo: "YesNo",
} as const
export type MessageBoxButtonType = typeof MessageBoxButtonTypes[keyof typeof MessageBoxButtonTypes]

const buttonType: MessageBoxButtonType = MessageBoxButtonTypes.Ok
const parentName = `callerTagName`

function btnName1(): string { return `${parentName}-b1` }

function createUI(htmlContent: string, title: string) {
    let btn1 = ``
    switch (buttonType) {
    case MessageBoxButtonTypes.Ok:
        btn1 = `<button id="${btnName1()}">`OK`</button>`
        break
    }

    const btnHTML = `${btn1}`
    const footer = `<div class="msg-footer">${btnHTML}</div>`

    const wrapper = document.createElement("div")
    wrapper.id = this.parentName
    wrapper.innerHTML = `
        <div class="msg-overlay">
            <div class="msg-panel">
                <div class="msg-header">${title}</div>
                <div class="msg-body">${htmlContent}</div>
                ${footer}
            </div>
        </div>
    `.trim()
    document.body.appendChild(wrapper)
}

イベント登録

const Result: MessageBoxResultType = MessageBoxResultTypes.None

const onB1Clicked = (event: Event) => {
    Result = MessageBoxResultTypes.Ok
    remove()
}
document.getElementById(this.btnName1)?.addEventListener("click", onB1Clicked, { once: true })

CSS

function applyCss() {
    const styleId = `${parentName}-style`;
    if (document.getElementById(styleId)) return;

    const style = document.createElement("style");
    style.id = styleId;
    style.textContent = `
#${parentName} .msg-overlay {
    position: fixed; top: 0; left: 0; width: 100vw; height: 100vh;
    background-color: rgba(0, 0, 0, 0.6);
    display: flex; justify-content: center; align-items: center;
    z-index: 10001;
}
`.trim();
        document.head.appendChild(style);
    }

※「z-index」について
他のダイアログが表示してあるときでも、「メッセージボックスを最前面」にするために、他のダイアログより大きな値を設定します。

後始末

function remove() {
    document.getElementById(btnName1())?.removeEventListener("click", onB1Clicked)
    document.getElementById(parentName)?.remove()
}

待つことが必要

ここまでの実装で、メッセージボックス表示はできたけど、「待ってくれない」問題が発覚した。
要するに、操作(「OK」をクリックした)をした後、後続の処理を進める必要があるということ。
状況をGeminiに説明すると、「Promise」というのを使えることを教えてもらった。

MDNに説明が載っていましたが、よく理解できなかったけど、要は、
・何かの条件が成立したとき、Promiseに通知すると待ちを解除してくれる
こんな感じらしい。
https://developer.mozilla.org/ja/docs/Web/JavaScript/Guide/Using_promises

最終形態

Promiseを考慮した実装は、こんな感じ。

const resolver!: (value: MessageBoxResultType) => void

function async showWait(htmlContent: string, title: string | null = null): Promise<MessageBoxResultType> {
    remove()
    createUI(htmlContent, title === null ? this.title : title, true); 
        
    return new Promise((resolve) => {
        resolver = resolve
        document.getElementById(btnName1())?.addEventListener("click", onB1Clicked, { once: true });
    }
}

const onB1Clicked = (event: Event) => {
    Result = MessageBoxResultTypes.Ok
    remove()
    if (resolver)
        resolver(Result)
}

※new Promise()、resolve について。
・new Promise()でインスタンスを作成すると、resolveを通知してくれる。そのあと、Promise内で待ちが発生する。
・resolveはコールバックみたいな関数で、呼び出すと待ちを解除してくれる。

つぎは。

表形式のUIを作っていこうと思った。TABLEタグを勉強しながら作ろうと思う。

つづく。
https://qiita.com/puyon/items/cb273b2c79a5b1ea1f1a

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?