كيفية إنشاء طريقة عرض مخصصة للتنبيه () والتأكيد () والموجه () للاستخدام في JavaScript

لطالما كنت أفكر في تخصيص مظهر وظائف تفاعل المستخدم النموذجية في جافا سكريبت - التنبيه () والتأكيد () والموجه () (فيما يلي النوافذ المشروطة).
في الواقع ، إنها مريحة جدًا في الاستخدام ، ولكنها مختلفة في المتصفحات المختلفة والمظهر القبيح جدًا.
أخيرا ، وصلت اليدين.
ما المشكلة؟ لا يمكن استخدام الوسائل المعتادة لعرض مربعات الحوار (على سبيل المثال ، bootstrap) كمجرد تنبيه ، حيث يرتب المتصفح لرمز JavaScript لإيقاف التنفيذ وينتظر أن يتصرف المستخدم (انقر على زر الإغلاق). يتطلب Modal في bootstrap معالجة حدث منفصلة - النقر على زر ، وإغلاق نافذة مشروط ...
ومع ذلك ، فقد استخدمت بالفعل تخصيص التنبيهات في الألعاب لاستبدال الرسائل القياسية بتلك التي تتوافق مع نمط تصميم اللعبة. يعمل هذا بشكل جيد ، بما في ذلك رسائل خطأ الاتصال وحالات النظام الأخرى. ولكن هذا لن يعمل إذا احتاج المستخدم إلى انتظار الرد!
صورة
مع ظهور Promise في ECMAScript 6 (ES6) ، كل شيء ممكن!
لقد طبقت نهج فصل تصميم النوافذ المشروطة والرمز (التنبيه () والتأكيد () والموجه ()). ولكن يمكنك إخفاء كل شيء في التعليمات البرمجية. ما يجذب مثل هذا النهج - يمكن تغيير التصميم في مشاريع مختلفة ، ولكن ببساطة على صفحات مختلفة أو اعتمادًا على الموقف.
النقطة السيئة حول هذا النهج هي الحاجة إلى استخدام أسماء العلامات (id) في كود النوافذ المشروطة ، وحتى في النطاق العالمي. لكن هذا مجرد مثال للمبدأ ، لذلك لن أركز على ذلك.

الحصول على الرمز للتنبيه


لذا ، دعنا نحلل الترميز (bootstrap و Font Awesome لرموز الخطوط) ورمز التنبيه (أستخدم jQuery):
    <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);
        });
    };

كما قلت أعلاه ، يتم استخدام الاسم العالمي PromiseAlert وفئات ترميز html للتعليمات البرمجية. في السطر الأول من التعليمات البرمجية ، يتم تمرير معلمة وظيفة التنبيه إلى نص الرسالة. بعد ذلك ، تعرض طريقة التمهيد نافذة مشروطة بخيارات معينة (تجعلها أقرب إلى التنبيه الأصلي). مهم! يتم تذكر النافذة المشروطة في متغير محلي ، والذي يستخدم أدناه من خلال الإغلاق.
أخيرًا ، يتم إنشاؤه وإعادته نتيجة تنبيه الوعد ، والذي ، نتيجة لإغلاق النافذة المشروطة ، يتم تنفيذ هذا الوعد.
الآن دعونا نرى كيف يمكن استخدام هذا التنبيه:
    $('p a[href="#"]').on('click', async (e) => {
        e.preventDefault();
        await alert('Promise based alert sample');
    });

في هذا المثال ، يتم عرض رسالة عند النقر فوق الارتباطات الفارغة داخل الفقرات. إعارة الانتباه! للامتثال للمواصفات ، يجب أن يسبق وظيفة التنبيه الكلمة الرئيسية المنتظرة ، ولا يمكن استخدامها إلا داخل الوظيفة باستخدام الكلمة الأساسية غير المتزامنة. هذا يسمح لك أن تتوقع في هذا المكان (سيتوقف النص البرمجي ، كما في حالة التنبيه الأصلي) ، إغلاق النافذة المشروطة.
ماذا سيحدث إذا لم يتم ذلك؟ يعتمد على منطق التطبيق الخاص بك (مثال على هذا النهج في الشكل أعلاه). إذا كانت هذه هي نهاية الكود أو إذا كانت الإجراءات الإضافية للكود لا تفرط في تحميل الصفحة ، فربما يكون كل شيء على ما يرام! تتدلى النافذة المشروطة حتى يغلقها المستخدم. ولكن إذا كان لا يزال هناك نوافذ مشروطة أو إذا تم إعادة تحميل الصفحة ، فهناك انتقال إلى صفحة أخرى ، فلن يرى المستخدم ببساطة نافذة مشروطك وسيتم تدمير المنطق. يمكنني القول أنه من خلال التجربة ، تعمل الرسائل المتعلقة بأخطاء (حالات) الخادم المختلفة أو من مكتبات الكود بشكل جيد مع تنبيهنا الجديد ، على الرغم من أنها لا تستخدم انتظارًا.

نقوم بتطوير نهج للتأكيد


دعنا نذهب أبعد من ذلك. بدون شك ، لا يمكن استخدام التأكيد إلا في الربط المتزامن / المنتظر ، مثل يجب أن يخبر الكود بالنتيجة التي يختارها المستخدم. هذا ينطبق أيضا على موجه. لذا تأكد:
    <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);
            });
        });
    };

هناك اختلاف واحد فقط - نحتاج إلى الإبلاغ عن اختيار المستخدم. يتم ذلك باستخدام متغير محلي آخر في الإغلاق - تأكيد. إذا تم الضغط على زر التأكيد ، يتم تعيين المتغير إلى true ، وتكون قيمته كاذبة بشكل افتراضي. حسنًا ، عند معالجة إغلاق نافذة مشروطة ، ترجع الدقة هذا المتغير.
هنا الاستخدام (مطلوب مع غير متزامن / انتظار):
    $('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');
    });

المضي قدما - نهج موجه


يتم تنفيذ المنطق أعلاه أيضًا مع موجه الاختبار. وترميزها ومنطقها على النحو التالي:
    <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);
            });
        });
    };

الفرق بين المنطق والتأكيد ضئيل. متغير محلي إضافي في الإغلاق prmpt. ولا تحتوي على قيمة منطقية ، ولكن سلسلة يدخلها المستخدم. من خلال الإغلاق ، تحل قيمته. ويتم تعيين قيمة لها فقط عند الضغط على زر التأكيد (من حقل الإدخال). بالمناسبة ، أهدرت هنا متغيرًا عالميًا آخر ، PromisePromptInput ، لمجرد رمز الاختزال والبديل. باستخدامه ، قمت بتعيين تركيز الإدخال (على الرغم من أنه يمكن القيام به في نهج واحد - إما بنفس الطريقة أو كما هو الحال في الحصول على القيمة).
يمكنك تجربة هذا النهج في العمل هنا . يقع الرمز على الرابط .
يبدو الأمر مثل هذا (على الرغم من أن الرابط أعلاه أكثر تنوعًا):
صورة

الإيدز


فهي لا تتعلق مباشرة بموضوع المقالة ، لكنها تكشف عن المرونة الكاملة للمنهج.
يتضمن هذا موضوعات التمهيد. أخذت مواضيع مجانية هنا .
تبديل اللغة باستخدام التثبيت التلقائي وفقًا للغة المتصفح. هناك ثلاثة أوضاع - تلقائي (عبر المتصفح) أو روسي أو إنجليزي (إجباري). يتم تثبيت الجهاز بشكل افتراضي.
ملفات تعريف الارتباط ( من هنا ) اعتدت على حفظ السمة واللغة.
يتم تبديل السمات ببساطة عن طريق تثبيت مقطع href css من الموقع أعلاه:
    $('#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);
    });

حسنًا ، أتذكر في ملفات تعريف الارتباط للاسترداد في التمهيد:
    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';
    }

من أجل الأقلمة ، استخدمت ملف localization.json الذي أنشأت فيه قاموسًا للمفاتيح باللغة الإنجليزية وقيمها باللغة الروسية. من أجل البساطة (على الرغم من أن الترميز أصبح أكثر تعقيدًا في بعض الأماكن) ، أتحقق فقط من العقد النصية البحتة عند الترجمة ، واستبدال مفتاح من قيمة.
    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();

لذلك من الصعب القيام به في الإنتاج (أفضل على الخادم) ، ولكن هنا يمكنني عرض كل شيء على العميل. لا يمكنني الوصول إلى الخادم إلا عند التغيير من الروسية إلى الإنجليزية - أفرط في تحميل الترميز الأصلي (location.reload).
هذه الأخيرة ، كما هو متوقع ، يتم إصدار الرسالة قبل التحميل وفقًا لخوارزمية المتصفح ، ولا يؤثر تأكيدنا على ذلك. في نهاية الكود توجد نسخة مُعلَّقة من هذه الرسالة - يمكنك تجربتها عند نقلها بنفسك.
    //window.onbeforeunload = function (e) {
    //    e.returnValue = 'Do you really want to finish the job?';
    //    return e.returnValue;
    //};

All Articles