前陣子找到 JavaScript 快顯通知套件 - NOTY,雖然原作者已不再維護,但評估它最符合我的需求,如要修改也在我的能力範圍,維持原判。但接二連三有讀者提到,老朋友 SweetAlert2 其實就有定時自動關閉及其他快顯通知所需功能,有「眾裡尋他千百度,驀然回首,那人卻在燈火闌珊處」的驚喜感,不試用看看好像說不過去。

經過研究,結論是 SweetAlert2 的確能實現類似 NOTY 的通知效果,但未必能取代,看應用情境需求。

SweetAlert2 有個 Toasts 範例,訊息可顯示於右上角倒數後自動隱藏,也提供關閉鈕,呈現效果如同一般快顯通知;若要像 NOTY 滑鼠移在訊息上停止倒數,可透過 didOpen 事件為訊息元素加 mouseenter、mouseleave 事件可實現。快顯模式的訊息也能加上確認、取消鈕,但它不會遮蔽網頁,若想強迫使用者按鈕後再繼續得自己加上遮罩,幸好之前上過單兵基本教練,這回再次派上用場。

花了點時間,我試著用 SweetAlert2 做出與 NOTY 幾乎相同的效果:

感覺不賴吧?程式範例如下:線上展示

<!DOCTYPE html>
<html>

<head>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/animate.css@4.0.0/animate.min.css" />
    <script src="//cdn.jsdelivr.net/npm/sweetalert2@11"></script>
    <style>
    </style>
</head>

<body>
    <button onclick="testToast()">Toast</button>
    <button onclick="testConfirm()">Confirm</button>
    <pre id="log"></pre>
    <script>
        const Toast = Swal.mixin({
            toast: true,
            position: 'top-right',
            showConfirmButton: false,
            showClass: {
                popup: 'animate__animated animate__fadeInRight'
            },
            hideClass: {
                popup: 'animate__animated animate__fadeOutRight'
            },
            timer: 2500,
            timerProgressBar: true,
            didOpen: toast => {
                toast.addEventListener('mouseenter', Swal.stopTimer);
                toast.addEventListener('mouseleave', Swal.resumeTimer);
            },
            showCloseButton: true
        });
        let i = 1;
        function testToast() {
            Toast.fire({
                icon: 'success', title: `資料更新完成${i++}`
            });
        }
        const logger = document.getElementById('log');
        function testConfirm() {
            Toast.fire({
                icon: 'question', title: '您確定要按下確定?',
                timer: false, showCloseButton: false,
                confirmButtonText: '確定', cancelButtonText: '取消',
                showConfirmButton: true, showCancelButton: true,
                buttonsStyling: false,
                didOpen: toast => {
                    const mask = document.createElement('div');
                    mask.setAttribute('id', 'swal2_toast_overlay');
                    mask.style = `position:absolute;top:0;left:0;width:100%;height:100%;z-index:1050;background-color:#444;opacity:0.5`;
                    document.body.appendChild(mask);
                },
                willClose: toast => {
                    const mask = document.getElementById('swal2_toast_overlay');
                    if (mask) mask.remove();
                    return true;
                }
            })
            .then((res) => logger.insertAdjacentText('beforeend',
                `已按下${res.value ? '確定' : '取消'}\n`));
        }
    </script>
</body>

</html>

接著來說說,SweetAlert2 不能取代 NOTY 的原因:它每次只能顯示一個對話框。小改程式,來看問題出在哪裡:

        let i = 1;
        function testToast() {
            Toast.fire({
                icon: 'success', title: `資料更新完成${i++}`
            });
        }

由於 SweetAlert2 是以 alert() 的概念出發,同一時間只會存在一個對話框,若連續觸發,訊息來不及顯示就被後面的訊息蓋掉。初步看了 Swal 程式碼及參考網路討論:

我認為這是 alert 本質及設計理念的限制,要魔改到一次顯示多訊息不是不可能,但這像人在豆漿燒餅店,堅持要吃白酒蛤蜊義大利麵,何苦來哉?

結論,如果你的快顯通知不存在一次多筆的應用需求,用 SweetAlert2 可一次滿足標準提示對話框及快顯通知兩種呈現方式,也是不錯的選擇。

Study of toast display mode of SweetAlert2 library.


Comments

# by Cash

人在豆漿燒餅店,堅持要吃白酒蛤蜊義大利麵 <== 這句話打到我了 XD

# by Tim

Alertify 也很不錯用喔

Post a comment