So erstellen Sie eine benutzerdefinierte Ansicht für alert (), verify () und prompt () zur Verwendung in JavaScript

Ich habe lange darüber nachgedacht, das Erscheinungsbild typischer Benutzerinteraktionsfunktionen in JavaScript anzupassen - alert (), verify () und prompt () (im Folgenden: modale Fenster).
In der Tat sind sie sehr bequem zu bedienen, unterscheiden sich jedoch in verschiedenen Browsern und sehen sehr unansehnlich aus.
Schließlich erreichten die Hände.
Was ist das Problem? Die üblichen Methoden zum Anzeigen von Dialogen (z. B. Bootstrap) können nicht so einfach verwendet werden wie Alarme, bei denen der Browser dafür sorgt, dass der JavaScript-Code nicht mehr ausgeführt wird und auf das Handeln des Benutzers wartet (klicken Sie auf die Schaltfläche zum Schließen). Modal in Bootstrap erfordert eine separate Ereignisbehandlung - Klicken Sie auf eine Schaltfläche und schließen Sie ein modales Fenster ...
Trotzdem habe ich bereits die Anpassung von Warnungen in Spielen verwendet, um Standardnachrichten durch solche zu ersetzen, die dem Stil des Spieldesigns entsprechen. Dies funktioniert gut, einschließlich Verbindungsfehlermeldungen und anderer Systemsituationen. Dies funktioniert jedoch nicht, wenn der Benutzer auf eine Antwort warten muss!
Bild
Mit dem Aufkommen von Promise in ECMAScript 6 (ES6) ist alles möglich!
Ich habe den Ansatz angewendet, das Design von modalen Fenstern und Code (alert (), verify () und prompt ()) zu trennen. Sie können jedoch alles im Code ausblenden. Was einen solchen Ansatz anzieht - das Design kann in verschiedenen Projekten geändert werden, aber einfach auf verschiedenen Seiten oder je nach Situation.
Der schlechte Punkt bei diesem Ansatz ist die Notwendigkeit, Markup-Namen (ID) im Code von Modalfenstern und sogar im globalen Bereich zu verwenden. Dies ist jedoch nur ein Beispiel für das Prinzip, daher werde ich mich nicht darauf konzentrieren.

Den Code für die Warnung erhalten


Schauen wir uns also das Markup (Bootstrap und Font Awesome für Schriftsymbole) und den Warncode (ich verwende jQuery) an:
    <div id="PromiseAlert" class="modal">
        <div class="modal-dialog" role="document">
            <div class="modal-content">
                <div class="modal-header">
                    <h5 class="modal-title"><i class="fas fa-exclamation-triangle text-warning"></i> <span>The app reports</span></h5>
                    <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                        <span aria-hidden="true">×</span>
                    </button>
                </div>
                <div class="modal-body">
                    <p></p>
                </div>
                <div class="modal-footer">
                    <button type="button" class="btn btn-secondary" data-dismiss="modal">OK</button>
                </div>
            </div>
        </div>
    </div>

    window.alert = (message) => {
        $('#PromiseAlert .modal-body p').html(message);
        var PromiseAlert = $('#PromiseAlert').modal({
            keyboard: false,
            backdrop: 'static'
        }).modal('show');
        return new Promise(function (resolve, reject) {
            PromiseAlert.on('hidden.bs.modal', resolve);
        });
    };

Wie oben erwähnt, werden der globale Name PromiseAlert und die HTML-Markup-Klassen für den Code verwendet. In der ersten Codezeile wird der Alarmfunktionsparameter an den Nachrichtentext übergeben. Danach zeigt die Bootstrap-Methode ein modales Fenster mit bestimmten Optionen an (sie bringen es näher an die native Warnung). Wichtig! Das modale Fenster wird in einer lokalen Variablen gespeichert, die unten durch Schließen verwendet wird.
Schließlich wird es als Ergebnis eines Alarmversprechens erstellt und zurückgegeben, in dem als Ergebnis des Schließens des modalen Fensters dieses Versprechen ausgeführt wird.
Nun wollen wir sehen, wie diese Warnung verwendet werden kann:
    $('p a[href="#"]').on('click', async (e) => {
        e.preventDefault();
        await alert('Promise based alert sample');
    });

In diesem Beispiel wird eine Meldung angezeigt, wenn Sie auf leere Links in Absätzen klicken. Aufpassen! Um der Spezifikation zu entsprechen, muss der Alert-Funktion das Schlüsselwort await vorangestellt werden. Sie kann nur innerhalb der Funktion mit dem Schlüsselwort async verwendet werden. Auf diese Weise können Sie erwarten, dass an dieser Stelle (das Skript stoppt, wie im Fall der nativen Warnung) das modale Fenster geschlossen wird.
Was passiert, wenn dies nicht getan wird? Hängt von der Logik Ihrer Anwendung ab (ein Beispiel für einen solchen Ansatz in der obigen Abbildung). Wenn dies das Ende des Codes ist oder weitere Aktionen des Codes die Seite nicht überladen, ist wahrscheinlich alles in Ordnung! Das modale Fenster hängt ab, bis der Benutzer es schließt. Wenn es jedoch noch modale Fenster gibt oder wenn die Seite neu geladen wird, gibt es einen Übergang zu einer anderen Seite, dann sieht der Benutzer Ihr modales Fenster einfach nicht und die Logik wird zerstört. Ich kann sagen, dass aus Erfahrung Nachrichten über verschiedene Serverfehler (Status) oder aus Codebibliotheken mit unserer neuen Warnung recht gut funktionieren, obwohl sie nicht auf Warten warten.

Wir entwickeln einen Ansatz zur Bestätigung


Gehen wir weiter. Bestätigen kann ohne Zweifel nur in der asynchronen / wartenden Bindung verwendet werden, da Er muss dem Code das Ergebnis der Wahl des Benutzers mitteilen. Dies gilt auch für Eingabeaufforderungen. Also bestätigen Sie:
    <div id="PromiseConfirm" class="modal">
        <div class="modal-dialog" role="document">
            <div class="modal-content">
                <div class="modal-header">
                    <h5 class="modal-title"><i class="fas fa-check-circle text-success"></i> <span>Confirm app request</span></h5>
                    <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                        <span aria-hidden="true">×</span>
                    </button>
                </div>
                <div class="modal-body">
                    <p></p>
                </div>
                <div class="modal-footer">
                    <button type="button" class="btn btn-success" data-dismiss="modal">OK</button>
                    <button type="button" class="btn btn-danger" data-dismiss="modal">Cancel</button>
                </div>
            </div>
        </div>
    </div>

    window.confirm = (message) => {
        $('#PromiseConfirm .modal-body p').html(message);
        var PromiseConfirm = $('#PromiseConfirm').modal({
            keyboard: false,
            backdrop: 'static'
        }).modal('show');
        let confirm = false;
        $('#PromiseConfirm .btn-success').on('click', e => {
            confirm = true;
        });
        return new Promise(function (resolve, reject) {
            PromiseConfirm.on('hidden.bs.modal', (e) => {
                resolve(confirm);
            });
        });
    };

Es gibt nur einen Unterschied - wir müssen über die Wahl des Benutzers informieren. Dies erfolgt mit einer anderen lokalen Variablen im Abschluss - bestätigen. Wenn die Bestätigungstaste gedrückt wird, wird die Variable auf true gesetzt und ihr Wert ist standardmäßig false. Wenn Sie das Schließen eines modalen Fensters verarbeiten, gibt resolve diese Variable zurück.
Hier ist die Verwendung (erforderlich mit async / await):
    $('p a[href="#"]').on('click', async (e) => {
        e.preventDefault();
        if (await confirm('Want to test the Prompt?')) {
            let prmpt = await prompt('Entered value:');
            if (prmpt) await alert(`entered: «${prmpt}»`);
            else await alert('Do not enter a value');
        }
        else await alert('Promise based alert sample');
    });

Weitermachen - ein Ansatz für die Aufforderung


Die obige Logik wird auch mit der Testaufforderung implementiert. Und sein Markup und seine Logik sind wie folgt:
    <div id="PromisePrompt" class="modal">
        <div class="modal-dialog" role="document">
            <div class="modal-content">
                <div class="modal-header">
                    <h5 class="modal-title"><i class="fas fa-question-circle text-primary"></i> <span>Prompt request</span></h5>
                    <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                        <span aria-hidden="true">×</span>
                    </button>
                </div>
                <div class="modal-body">
                    <div class="form-group">
                        <label for="PromisePromptInput"></label>
                        <input type="text" class="form-control" id="PromisePromptInput">
                    </div>
                </div>
                <div class="modal-footer">
                    <button type="button" class="btn btn-success" data-dismiss="modal">OK</button>
                    <button type="button" class="btn btn-danger" data-dismiss="modal">Cancel</button>
                </div>
            </div>
        </div>
    </div>

    window.prompt = (message) => {
        $('#PromisePrompt .modal-body label').html(message);
        var PromisePrompt = $('#PromisePrompt').modal({
            keyboard: false,
            backdrop: 'static'
        }).modal('show');
        $('#PromisePromptInput').focus();
        let prmpt = null;
        $('#PromisePrompt .btn-success').on('click', e => {
            prmpt = $('#PromisePrompt .modal-body input').val();
        });
        return new Promise(function (resolve, reject) {
            PromisePrompt.on('hidden.bs.modal', (e) => {
                resolve(prmpt);
            });
        });
    };

Der Unterschied zwischen Logik und Bestätigung ist minimal. Eine zusätzliche lokale Variable im Abschluss ist prmpt. Und es hat keinen logischen Wert, sondern eine Zeichenfolge, die der Benutzer eingibt. Durch die Schließung löst sich sein Wert auf. Und ein Wert wird ihm nur zugewiesen, wenn die Bestätigungstaste gedrückt wird (aus dem Eingabefeld). Übrigens habe ich hier eine andere globale Variable verschwendet, PromisePromptInput, nur für Kurzschrift und alternativen Code. Damit setze ich den Eingabefokus (obwohl dies in einem einzigen Ansatz erfolgen kann - entweder auf die gleiche Weise oder wie beim Abrufen des Werts).
Sie können diesen Ansatz in Aktion versuchen hier . Der Code befindet sich unter dem Link .
Es sieht ungefähr so ​​aus (obwohl der obige Link vielfältiger ist):
Bild

Aids


Sie beziehen sich nicht direkt auf das Thema des Artikels, zeigen jedoch die volle Flexibilität des Ansatzes.
Dies schließt Bootstrap-Themen ein. Ich habe freie Themen hier .
Wechseln Sie die Sprache mithilfe der automatischen Installation entsprechend der Browsersprache. Es gibt drei Modi - automatisch (über Browser), Russisch oder Englisch (erzwungen). Die Maschine ist standardmäßig installiert.
Cookies ( von hier ) Ich habe mir das Thema und den Sprachwechsel gemerkt.
Die Themen wechseln einfach durch Installieren des href css-Segments von der oben genannten Site:
    $('#themes a.dropdown-item').on('click', (e) => {
        e.preventDefault();
        $('#themes a.dropdown-item').removeClass('active');
        e.currentTarget.classList.add('active');
        var cur = e.currentTarget.getAttribute('href');
        document.head.children[4].href = 'https://stackpath.bootstrapcdn.com/bootswatch/4.4.1/' + cur + 'bootstrap.min.css';
        var ed = new Date();
        ed.setFullYear(ed.getFullYear() + 1);
        setCookie('WebApplicationPromiseAlertTheme', cur, ed);
    });

Nun, ich erinnere mich an Cookies zur Wiederherstellung beim Booten:
    var cookie = getCookie('WebApplicationPromiseAlertTheme');
    if (cookie) {
        $('#themes a.dropdown-item').removeClass('active');
        $('#themes a.dropdown-item[href="' + cookie + '"]').addClass('active');
        document.head.children[4].href = 'https://stackpath.bootstrapcdn.com/bootswatch/4.4.1/' + cookie + 'bootstrap.min.css';
    }

Für die Lokalisierung habe ich die Datei localization.json verwendet, in der ich ein Wörterbuch mit Schlüsseln auf Englisch und deren Werten auf Russisch erstellt habe. Der Einfachheit halber (obwohl das Markup an einigen Stellen komplizierter geworden ist) überprüfe ich während der Übersetzung nur reine Textknoten und ersetze den Schlüssel durch Werte.
    var translate = () => {
        $('#cultures .dropdown-toggle samp').text({ ru: '  ', en: ' English ' }[culture]);
        if (culture == 'ru') {
            let int;
            if (localization) {
                for (let el of document.all)
                    if (el.childElementCount == 0 && el.textContent) {
                        let text = localization[el.textContent];
                        if (text) el.textContent = text;
                    }
            }
            else int = setInterval(() => {
                if (localization) {
                    translate();
                    clearInterval(int);
                }
            }, 100);
        }
        else location.reload();
    };
    if (culture == 'ru') translate();

In der Produktion ist das kaum gut (besser auf dem Server), aber hier kann ich alles auf dem Client demonstrieren. Ich greife nur auf den Server zu, wenn ich von Russisch auf Englisch wechsle. Ich überlade nur das ursprüngliche Markup (location.reload).
Letzteres wird erwartungsgemäß die Nachricht in onbeforeunload gemäß dem Browser-Algorithmus ausgegeben, und unsere Bestätigung hat keinen Einfluss darauf. Am Ende des Codes befindet sich eine kommentierte Version einer solchen Nachricht. Sie können sie ausprobieren, wenn Sie sie selbst übertragen.
    //window.onbeforeunload = function (e) {
    //    e.returnValue = 'Do you really want to finish the job?';
    //    return e.returnValue;
    //};

All Articles