Vue.js フロントエンド Web ページ ポップアップ非同期動作例の分析

Vue.js フロントエンド Web ページ ポップアップ非同期動作例の分析

1. 序文

Web ページのポップアップ ボックスは、ユーザーにメッセージを通知する必要がある場合 (アラート)、ユーザーに確認する必要がある場合 (確認)、ユーザーが情報を追加する必要がある場合 (プロンプト) など、非常に一般的な機能です。ユーザーがフォームに入力できるようにボックスをポップアップ表示することもできます (モーダル ダイアログ)。

ポップアップ ウィンドウが表示された後、開発者は次の操作を続行するために、ポップアップ ウィンドウがいつ閉じられるかを知る必要があります。

古い UI コンポーネントでは、これは次のようなイベント コールバックを通じて実行されます。

showDialog(コンテンツ、タイトル、{
    closed: function() { console.log("ダイアログボックスが閉じられました"); }
})

ただし、ダイアログ ボックスの動作。ご覧のとおり、ポップアップは表示されますが、後続のコードはブロックされず、ユーザーの動作であるため、開発者はいつ閉じられるかわかりません。非同期なので、Promise にカプセル化し、 await構文を使用して呼び出す方が快適です。シンプルなパッケージは次のようになります。

非同期関数 asyncShowDialog(コンテンツ、タイトル、オプション) {
    新しいPromiseを返します(resolve => {
        showDialog(コンテンツ、タイトル、{
            ...オプション、
            終了: 解決済み
        });
    });
}
 
(非同期() => {
    asyncShowDialog(コンテンツ、タイトル) を待機します。
    console.log("ダイアログ ボックスが閉じられました");
})();

ポップアップ ウィンドウの基本的な非同期動作は、このように単純です。それだけですか?それでも満足できない場合は、さらに勉強してください。

2. ポップアップコンポーネントを2つ見つける

Ant Design Vue はイベント形式を使用します。「OK」ボタンをクリックするとokイベントがトリガーされ、「キャンセル」または右上隅の閉じるボタンをクリックするとcancelイベントがトリガーされます。

これら 2 つのイベント処理関数は、パラメーター オブジェクトのonOkプロパティとonCancelプロパティを通じてマウントされます。一見シンプルに見えますが、イベント ハンドラーが Promise オブジェクトを返すと、ボタンをクリックした後に読み込みアニメーションが表示され、Promise オブジェクトが完了するまでダイアログ ボックスは閉じられません。このデザインは、非同期の待機アニメーションをポップアップ ウィンドウに組み合わせたもので、シンプルで直感的であり、コードも簡単に記述できます。確認ダイアログボックスを例に挙げます。

モーダル.確認({
    ...
    オンOK() {
        // 「OK」ボタンをクリックすると、読み込みアニメーションが表示され、1秒後にダイアログボックスが閉じられます return new Promise(resolve => {
            タイムアウトを設定します(解決、1000);
        });
    }
    ...
});

Element Plus は Promise 形式を使用します。ダイアログボックスを開くときに、確認またはキャンセル処理関数をパラメータとして渡すのではなく、開発者が.then()/.catch()またはawaitを通じて処理できるように Promise オブジェクトを直接返します。例:

試す {
    ElMessageBox.confirm(...) を待機します。
    // ここで処理するにはOKボタンを押します} catch(err) {
    // キャンセルボタンの押下はここで処理されます }

Element Plus 処理方法では、ダイアログ ボックスが閉じられた後にのみビジネスを処理できる必要があります。これは Promise を使用する場合の制限でもあります。すでにカプセル化された Promise オブジェクトに新しいロジックを挿入することは困難です。

Ant Design のようにElMessageBox閉じる前に非同期操作を実行したい場合は、閉じる前に処理イベントを提供しているかどうかを確認することしかできません。実際にしばらく探した後、見つけました。beforeClose beforeCloseがあります。イベント ハンドラのシグネチャはbeforeClose(action, instance, done)です。

actionどのボタンが押されたかを示し、可能な値は"confirm""cancel""close"です (説明は不要です)。

instanceはMessageBoxインスタンスであり、次のようなインターフェース効果を制御するために使用できます。

instance.confirmButtonLoading = true 、「OK」ボタンに読み込みアニメーションを表示し、 instance.confirmButtonTextを使用してボタンのテキストを変更できます...これらの操作により、非同期待機を実行するときにユーザー エクスペリエンスが向上します。

done beforeClose()の非同期処理が完了し、ダイアログ ボックスを閉じることができることを示すために呼び出される関数です。

したがって、Ant Design のような処理は次のように記述できます。

試す {
    ElMessageBox.confirm({を待つ
        ...
        beforeClose: async (アクション、インスタンス、完了) => {
            新しい Promise(resolve => setTimeout(resolve, 1000)) を待機します。
            終わり();
        }
    });
    // ここで処理するにはOKボタンを押します} catch(err) {
    // キャンセルボタンの押下はここで処理されます }

3. 自分で作る

2 つの弾丸ボックス コンポーネントの動作処理を分析した結果、優れたエクスペリエンスを備えた弾丸ボックス コンポーネントには次の特性があることがわかっています。

  • Promise ベースの非同期制御機能を提供します (Ant Design Vue ではこの機能は提供されませんが、「シーケンス」のようにカプセル化できます)。
  • 非同期操作であっても、閉じる前にいくつかの操作を実行できるようにします。
  • 非同期読み込みプロセス中にインターフェースフィードバックを提供し、開発者の制御を必要としないことが最善です (この点では、Ant Design は Element Plus よりも便利です)。

次に、自分で書いて、上記の機能をどのように実装するかを見てみましょう。ただし、今回はデータ処理ではなく動作を主に学習するため、Vue フレームワークは使用せず、DOM 操作を直接使用し、その後 jQuery を導入して DOM 処理を簡素化します。

ダイアログ ボックスの HTML スケルトンも比較的シンプルです。下部にマスク レイヤー、上部に固定サイズの<div>レイヤーがあり、内部の<div>タイトル、コンテンツ、操作領域の 3 つの領域に分かれています。

<div class="ダイアログ" id="ダイアログテンプレート">
  <div class="ダイアログウィンドウ">
    <div class="dialog-title">ダイアログボックスのタイトル</div>
    <div class="dialog-content">ダイアログコンテンツ</div>
    <div class="ダイアログ操作">
      <button type="button" class="ensure-button">確認</button>
      <button type="button" class="cancel-button">キャンセル</button>
    </div>
  </div>
</div>

ここではテンプレートとして定義されており、プレゼンテーションのたびにそこから DOM を複製し、閉じられたときに破棄したいと考えています。

スタイルシートの内容は長いので、以下のサンプルリンクから取得できます。この記事の焦点はコードとその進化です。

最も簡単な方法は、jQuery を使用して複製して表示することですが、表示する前に、必ずid属性を削除して<body>に追加してください。

$("#dialogTemplate").clone().removeAttr("id").appendTo("body").show();

これを関数にラップし、「OK」ボタンと「キャンセル」ボタンの処理を追加します。

関数 showDialog(コンテンツ, タイトル) {
    定数 $dialog = $("#dialogTemplate").clone().removeAttr("id"); 
    // ダイアログ ボックスのタイトルと内容を設定します (簡単な例なので、テキストのみを処理します)
    $dialog.find(".dialog-title").text(タイトル);
    $dialog.find(".dialog-content").text(コンテンツ); 
    // イベント プロキシ経由で (またはプロキシなしで) 2 つのボタン イベントを処理します $dialog
        .on("クリック", ".ensure-button", () => {
            ダイアログを削除します。
        })
        .on("クリック", ".cancel-button", () => {
            ダイアログを削除します。
        }); 
    $dialog.appendTo("body").show();
}

ポップアップ ウィンドウの基本的なロジックが明らかになります。ここで、2 つの最適化を行います。① $dialog.remove()を関数にカプセル化して、ダイアログボックスを閉じる処理を統一的に行う (コードの再利用) ② .show()の使用は唐突すぎるため、 fadeIn(200)変更します。同様に、 fadeOut(200) .remove()の前に呼び出す必要があります。

関数 showDialog(...) {
    ... 
    定数を破棄 = () => {
        $dialog.fadeOut(200, () => $dialog.remove());
    }; 
    $ダイアログ
        .on("クリック", ".ensure-button", 破棄)
        .on("クリック", ".cancel-button", 破棄); 
    $dialog.appendTo("body").fadeIn(200);
}

3.1. Promiseのカプセル化

この時点では、ポップアップ ウィンドウを正常に表示/閉じることはできますが、「OK」または「キャンセル」ロジック コードを挿入する方法はありません。前述のように、インターフェースはイベントまたはプロミスの 2 つの形式で提供できます。ここでは、プロミス メソッドを使用します。 「OK」をクリックすると解決され、「キャンセル」をクリックすると拒否されます。

関数 showDialog(...) {
    ... 
    const promise = new Promise((resolve, deny) => {
        $ダイアログ
            .on("クリック", ".ensure-button", () => {
                破壊する();
                解決します("OK");
            })
            .on("クリック", ".cancel-button", () => {
                破壊する();
                拒否("キャンセル");
            });
    }); 
    $dialog.appendTo("body").fadeIn(200);
    promise() を返します。
}

カプセル化は完了しましたが、問題があります。destroy destroy()は非同期プロセスですが、コードはそれが完了するまで待機しないため、 showDialog()非同期処理を完了した後も、 fadeOut()およびremove()操作がまだ実行されています。この問題を解決するには、 destory()をカプセル化するしかありません。もちろん、呼び出すときにawaitを追加することを忘れないでください。また、 awaitを追加するには、外側の関数をasyncとして宣言する必要があります。

関数 showDialog(...) {
    ...
    定数を破棄 = () => {
        新しいPromiseを返します(resolve => {
            $dialog.fadeOut(200, () => {
                ダイアログを削除します。
                解決する();
            });
        });
    };
     const promise = new Promise((resolve, deny) => {
        $ダイアログ
            .on("クリック", ".ensure-button", 非同期() => {
                破棄を待ちます。
                解決します("OK");
            })
            .on("クリック", ".cancel-button", 非同期() => {
                破棄を待ちます。
                拒否("キャンセル");
            });
    }); 
    ...
}

3.2. 特定の場合に非同期待機を許可する

「確認」をクリックしても「キャンセル」をクリックしても、非同期待機のためにポップアップ ウィンドウが表示されたままになります。ただし、例として、ここでは「OK」のケースのみを扱います。

この非同期待機プロセスはポップアップ ウィンドウに挿入する必要があり、パラメータの形式でのみ挿入できます。したがって、処理関数をonOkプロパティに挿入できるようにshowDialog()optionsパラメータを追加する必要があります。この処理関数が Promise Like を返すと、非同期待機が実行されます。

まず、 showDialog()インターフェースを変更します。

関数 showDialog(コンテンツ、タイトル、オプション = {}) { ... }

次に、$dialog.on("click", ".ensure-button", ...) イベントを処理します。

$ダイアログ
    .on("クリック", ".ensure-button", 非同期() => {
        const { onOk } = オプション;
        // オプションから onOk を取得します。関数の場合は、処理を待つ必要があります if (typeof onOk === "function") {
            定数 r = onOk();
            // onOk() の結果が Promise のようなオブジェクトかどうかを判定します // Promise のようなオブジェクトのみが非同期待機を必要とします if (typeof r?.then === "function") {
                定数 $button = $dialog.find(".ensure-button");
                // 非同期の待機プロセス中に、ユーザーに何らかのフィードバックを提供する必要があります // ここでは面倒なので、読み込みアニメーションは使用せず、フィードバックにはテキストのみを使用します $button.text("処理中...");
                rを待つ;
                // 完了後、閉じる前に 200 ミリ秒のフェードアウト プロセスがあるため、
                // したがって、ユーザーにタイムリーなフィードバックを提供するために、ボタンのテキストを「完了」に変更する必要があります $button.text("Done");
            }
        }
        破棄を待ちます。
        解決します("OK");
    })

これで、このポップアップ ボックスの動作は基本的に処理され、呼び出し例は次のようになります。

const 結果 = showDialog を待機します(
    「こんにちは、これがダイアログボックスの内容です」
    「こんにちは」
    {
        onOk: () => 新しい Promise((resolve) => { setTimeout(resolve, 3000); })
    }
).catch(msg => msg); // ここでは、キャンセルによって発生した拒否が、try...catch... の使用を避けるために解決に変換されます。
 
console.log(result === "ok" ? "OKを押してください" : "キャンセルを押してください");

3.3. 詳細を改善する

ダイアログボックスの最後にconsole.log(...)を使用するのは少し不適切です。プロンプトメッセージを直接ポップアップする方がよいのではないでしょうか。

しかし、現在、 showDialog()は確認ポップアップ ボックスのみを処理し、アラート ポップアップ ボックスは処理しません... これは大きな問題ではなく、 optionstypeを追加するだけです。 type"alert"の場合は、「キャンセル」ボタンを削除します。

非同期関数 showDialog(コンテンツ、タイトル、オプション = {}) {
    ...
    
    if (options.type === "alert") {
        $dialog.find(".キャンセルボタン").remove();
    }    
    ...
}

次に、最終的なconsole.log(...)次のように展開します。

showDialog(result === "ok" ? "OKを押してください" : "キャンセルを押してください", "プロンプト", { type: "alert" });

3.4. 改革

optionsに処理関数を挿入したくない場合は、返された Promise オブジェクトに挿入することもできます。まず、 .ensure-buttonイベントでconst { onOk } = options const { onOk } = promise変更します。つまり、挿入されたonOk promiseから取得します。次に、呼び出し部分を変更します。

const dialog = showDialog("こんにちは、これがダイアログ ボックスの内容です", "こんにちはと言ってください");
// 処理関数をPromiseのonOkに挿入する
dialog.onOk = () => 新しい Promise((resolve) => { setTimeout(resolve, 3000); });
const 結果 = dialog.catch(msg => msg) を待機します。
showDialog(result === "ok" ? "OKを押してください" : "キャンセルを押してください", "プロンプト", { type: "alert" });

ここで注意すべき点がいくつかあります:

dialog showDialog()から直接返される必要があります。 .catch()を呼び出すと、別の Promise オブジェクトが取得されます。このとき、 onOkを注入しても、 showDialog()で生成された Promise オブジェクトに注入することはできません。

showDialog() asyncとして宣言できません。そうしないと、返される Promise オブジェクトは内部で生成されたものとは異なります。

awaitを忘れないでください。

上記は、vue.js フロントエンド Web ページ ポップアップ ボックスの非同期動作の例の詳細な分析です。vue.js フロントエンド非同期 Web ページ ポップアップ ボックスの詳細については、123WORDPRESS.COM の他の関連記事に注目してください。

以下もご興味があるかもしれません:
  • 一般的なポップアップウィンドウ/ドラッグアンドドロップ/非同期ファイルアップロードなどの実用的なコード
  • JavaScript で作成された Web ページのサイド ポップアップ ボックスのアイデアと実装コード
  • jQuery+Ajax+PHP ポップアップ レイヤー非同期ログイン効果 (ソース コードのダウンロード付き)
  • JavaScript 非同期 innerHTML の使用状況の分析
  • JSはWebページ上に入力ボックスをポップアップする方法を実装します

<<:  ウェブ標準学習リソースの素晴らしいコレクション

>>:  CSS3 カスタムスクロールバースタイル::webkit-scrollbar サンプルコード詳細説明

推薦する

CSS3 でテキストマーキーを実装するためのサンプルコード

背景何が起こったかというと、Luzhu は偶然、宇宙で最高の外部スピーカーを備えた携帯電話について知...

CSS を使用して HTML フォーム コントロールを美しくする詳細な例 (フォームの美化)

1. HTML送信ボタンと下部ボタンの基本構文構造1. HTML送信ボタン入力タグで type=&...

MySQLグループクエリ最適化方法

MySQL はほとんどの場合、GROUP BY クエリと DISTINCT クエリを同様に処理します...

jsはreduceメソッドを使用してコードをよりエレガントにします

序文実際のプロジェクトでは、最も一般的な処理は計算とループロジックである可能性があります。配列でre...

ページのキャッシュを防ぐソリューション

解決: <head> に次のコードを追加します。コードをコピーコードは次のとおりです。 ...

WeChatアプレットがチャットルーム機能を実現

この記事では、参考のために、WeChatアプレットのチャットルームを実装するための具体的なコードを例...

MySQL データベースにおける高同時実行性の問題を解決する方法

序文スタートアップ企業が最初はモノリシック アプリケーションを主要なアーキテクチャとして使用し、通常...

Docker-compose ネットワークの詳細な例

今日は Docker でのネットワーク設定を試し、後で忘れないようにプロセスを記録しました。 (シス...

MySQLが基礎データ構造としてB+ツリーを使用する理由

MySQL の基盤となるデータ構造が B+ ツリーであることは誰もが知っていますが、ではなぜ赤黒ツリ...

MySQL 5.7 および 8.0 データベースのルート パスワードを忘れた場合の解決策

注: MySQL5.7 で root パスワードをクラックするには、パスワード認証をスキップしてデー...

JavaScript オブジェクト指向クラス継承ケースの説明

1. オブジェクト指向のクラス継承これまでの章では、JavaScript のオブジェクト モデルがプ...

Web フォントの読み込みを最適化する方法をご存知ですか?

タイトル通りです!一般的に使用される font-family はブラウザの組み込みフォントを読み込み...

MySql データベースのサブクエリと高度なアプリケーションの簡単な分析

MySql データベースのサブクエリ:サブクエリ: 選択クエリ ステートメント内に別の選択ステートメ...

Linuxサーバー間のリアルタイムファイル同期の実現

使用シナリオ既存のサーバー A と B の場合、サーバー A の指定されたディレクトリ (たとえば、...

ウェブデザイン研究における XHTML の応用の概要

<br />一般的に、「標準的な Web ページ」のファイル構成は XHTML CSS ...