[JS] 使用Snackbar套件簡易實現Google網站的Notification

此套件致敬Google Material Design的Snackbars

前言

最近開發的Google Material Style網站(範例:https://agmstudio.io/themes/material-style/2.3.1/component-snackbar.html)

引用到的JS Notification套件:SnackBar,發現除了配色外,其餘長得很像Google網站的Notification ↓

此套件容易上手、寫的程式碼也少  ※相比之下,w3schools教你從頭寫到尾的教學就有點複雜:How TO - Snackbar / Toast

但官網文件隱藏很多沒公開的知識,所以寫此篇文章整理一下我發現的祕技XD

實作

進入官網:https://www.polonel.com/snackbar/

點擊Download下載壓縮包並解壓縮

接著到SnackBar-master\dist目錄下把snackbar.css、snackbar.js兩個檔案放置到自己Web專案內引用到網頁上即可

基本使用方法在<script>區段內寫下↓

Snackbar.show({ text: '範例文字' }); 

完整Html程式碼↓

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>My Demo SnackBar</title>
    <!--引用snackbar.css-->
    <link href="dist/snackbar.css" rel="stylesheet" />
</head>
<body>

    <!--引用snackbar.js-->
    <script src="dist/snackbar.js"></script>
    <script type="text/javascript">
        window.onload = function () {
            //基本用法↓
            Snackbar.show({ text: '範例文字' });
        }
    </script>
</body>
</html>

基本執行效果↓,Notification會出現在網頁的左下角

官網文件沒告訴你的事(祕技?)

祕技1:此套件不相依於jQuery

也就是說Web專案有使用到jQuery的話,jQuery不管怎麼改版都不會影響到此套件的使用。

這件事我自己完整survey過它的snackbar.js原始碼才知道

GitHub連結:https://github.com/polonel/SnackBar

可以留意當在呼叫Snackbar.show()時,它不使用jQuery的$.extend()來merge預設參數,而是另外寫一個仿$.extend()的原生JS function來merge使用者傳入的參數

※多學到一種Pure JS Extend寫法XD:http://gomakethings.com/vanilla-javascript-version-of-jquery-extend/

祕技2:官網文件的Default參數有誤

以下是官網的12個參數說明,很簡單明瞭,就不再用中文重新詮釋,不過留意以下劃紅線的三個參數

該三個參數,Default值正確如下↓

祕技3:其實還有四個參數可以控制顯示第二顆按鈕

看到上述的原始碼可以發現,其實還有showSecondButton、secondButtonText、secondButtonTextColor、onSecondButtonClick這幾個參數可以使用

雖然官網文件沒說明,但從參數名稱來看,應該也推測得出來是什麼用途,完整Html範例如下↓

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>My Demo SnackBar</title>
    <!--引用snackbar.css-->
    <link href="dist/snackbar.css" rel="stylesheet" />
</head>
<body>

    <!--引用snackbar.js-->
    <script src="dist/snackbar.js"></script>
    <script type="text/javascript">
        window.onload = function () {
            
            Snackbar.show({
                text: '儲存至「資料庫」',
                //第二顆按鈕用法↓
                showSecondButton: true, secondButtonText: "查看奇摩", secondButtonTextColor: "#64b5f6", onSecondButtonClick: function (element)
                {
                    window.location.href = "http://tw.yahoo.com";
                }
            });
        }
    </script>
</body>
</html>

執行結果↓

我想隱藏的四個參數(第二顆按鈕)是想要完全仿效Google的UI吧XD

但是Google本家的關閉Notification按鈕是「✖」 、「✕」(我使用嘸蝦米輸入法,叉叉還能打出來)

要把預設的綠色DISMISS字串改掉的話,得修改兩個參數:actionText、actionTextColor ↓

 Snackbar.show({
 text: '儲存至「資料庫」',
 //改這兩行
 actionText: "✕",//叉叉字串
 actionTextColor: '#fff', //白色
 //第二顆按鈕用法↓
 showSecondButton: true, secondButtonText: "查看奇摩", secondButtonTextColor: "#64b5f6", 
 onSecondButtonClick: function (element) {
   window.location.href = "http://tw.yahoo.com";
 }
              });

或進階一點使用fontawesome 5的圖示,完整Html代碼如下↓

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>My Demo SnackBar</title>
    <!--引用snackbar.css-->
    <link href="dist/snackbar.css" rel="stylesheet" />
</head>
<body>
  
    <!--引用fontawesome icon-->
    <script defer src="https://use.fontawesome.com/releases/v5.0.13/js/all.js" integrity="sha384-xymdQtn1n3lH2wcu0qhcdaOpQwyoarkgLVxC/wZ5q7h9gHtxICrpcaSUfygqZGOe" crossorigin="anonymous"></script>
    <!--引用snackbar.js-->
    <script src="dist/snackbar.js"></script>
    <script type="text/javascript">
        window.onload = function () {

            Snackbar.show({
                text: '儲存至「資料庫」',
                //改這兩行
                actionText: "<i class='fas fa-times'></i>",//fontawesome icon
                actionTextColor: '#fff', //白色 
                //第二顆按鈕用法↓
                showSecondButton: true, secondButtonText: "查看奇摩", secondButtonTextColor: "#64b5f6",
                onSecondButtonClick: function (element) {
                    window.location.href = "http://tw.yahoo.com";
                }
            });
              
        }
    </script>
</body>
</html>

另外補充:Google本家的Notification位置在網頁的正下方,而且關閉動作的Notification是往下滑出去(但此套件點擊關閉按鈕會直接淡出)

所以要幾乎仿效Google Style Notification的話,程式碼如下

    Snackbar.show({
                text: '儲存至「資料庫」', 
                pos: 'bottom-center',//出現位置為畫面正下方
                actionText: "✕",  //關閉按鈕文字
                actionTextColor: '#fff', //白色
                onActionClick: function (element) {//當點擊關閉按鈕時
                    //element為<div class="snackbar-container"></div> 
                    let sty = element.style;
                    //由於snackbar.css有定義.snackbar-container的transition,所以下面兩行會有轉場動畫效果
                    sty.bottom = "-100px"; //往下滑動
                    sty.opacity = 0;//淡出消失 
                }, 
                //第二顆按鈕用法↓
                showSecondButton: true, secondButtonText: "查看奇摩", secondButtonTextColor: "#64b5f6",
                onSecondButtonClick: function (element) {
                    window.location.href = "http://tw.yahoo.com";
                }
            });

執行結果↓

程式碼寫到此,應該已經發覺要傳遞的參數實在太多,這邊提供一種自訂預設值的寫法

先新增一個.js檔命名為MysnackbarSetting.js,裡面的程式碼放置最常使用到的參數↓

//宣告一個物件
let MysnackbarOption = { 

    actionText: "✕",  //關閉按鈕文字
    actionTextColor: '#fff', //關閉按鈕顏色 白色
    pos: 'bottom-center',//出現位置為畫面正下方  
    onActionClick: function (element) {//當點擊關閉按鈕時
        //element為<div class="snackbar-container"></div> 
        let sty = element.style;
        //由於snackbar.css有定義.snackbar-container的transition,所以下面兩行會有轉場動畫效果
        sty.bottom = "-100px"; //往下滑動
        sty.opacity = 0;//淡出消失 
    }

};

接著網頁引用該MysnackbarSetting.js,完整Html代碼如下↓

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>My Demo SnackBar</title>
    <!--引用snackbar.css-->
    <link href="dist/snackbar.css" rel="stylesheet" />
</head>
<body>
      
    <!--引用jQuery-->
    <script type="text/javascript" src="https://code.jquery.com/jquery-3.3.1.js"></script>
    <!--引用snackbar.js-->
    <script src="dist/snackbar.js"></script>
    <!--引用最常使用到的參數-->
    <script src="dist/MysnackbarSetting.js"></script>
    <script type="text/javascript">
        window.onload = function () { 

            Snackbar.show($.extend(true,MysnackbarOption,
                          { //寫下此頁面才會使用到的參數
                            text: "已儲存至資料庫"
                          })
            );//end show
        }
    </script>
</body>
</html>

執行結果↓

祕技4:執行Snackbar.close() 可以手動關閉Notification

不過該留意的是,預設它會以淡出行為去關閉Notification,請見原始碼↓

如果在執行Snackbar.close()時,想要關閉行為是往下滑出去的話,可以在剛剛的MysnackbarSetting.js檔裡寫下↓

//宣告一個物件
let MysnackbarOption = { 

    actionText: "✕",  //關閉按鈕文字
    actionTextColor: '#fff', //關閉按鈕顏色 白色
    pos: 'bottom-center',//出現位置為畫面正下方  

    onActionClick: MySnackbarClose//當點擊關閉按鈕時 
};

function MySnackbarClose()
{
    if (Snackbar.current)//防呆
    {
        //Snackbar.current 為 <div class="snackbar-container"></div>
        let sty = Snackbar.current.style;
        //由於snackbar.css有定義.snackbar-container的transition,所以下面兩行會有轉場動畫效果
        sty.bottom = "-100px"; //往下滑動
        sty.opacity = 0;//淡出消失 
         
    }
}

//改寫close function
Snackbar.close = MySnackbarClose;

完整Html的使用範例↓

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>My Demo SnackBar</title>
    <!--引用snackbar.css-->
    <link href="dist/snackbar.css" rel="stylesheet" />
</head>
<body>
      
    <button id="btn">button</button>

    <!--引用jQuery-->
    <script type="text/javascript" src="https://code.jquery.com/jquery-3.3.1.js"></script>
    <!--引用snackbar.js-->
    <script src="dist/snackbar.js"></script>
    <!--引用自訂參數-->
    <script src="dist/MysnackbarSetting.js"></script>
    <script type="text/javascript">
        $(function () {


            Snackbar.show($.extend(true, MysnackbarOption,
                { //寫下此頁面才會使用到的參數
                    text: "已儲存至資料庫"
                })
            );//end show

            //當click畫面上的button
            $("#btn").click(function () {
                //手動執行關閉
                Snackbar.close();
            });//end click
        });
        
         
    </script>
</body>
</html>

其它補充

Snackbar此套件一次只會出現一個Notification就如同Google網站一樣(其它Notification套件有些會重複出現)

當第二個Notification出現時,前一個Notification就會被移除掉

也就是說,你不會看到以下情況↓

如果有傳遞customClass參數

留意自訂的ClassName出現的位置在最外層的容器 <div class="snackbar-container"></div>

有個地方可能會被原始碼檢測誤判Client DOM Code Injection漏洞

僅管Notification呈現的文字都是程式設計師自己給的,並非抓前端user給的value

但還是有可能會被原始碼檢測誤判漏洞

問題出在以下的.innerHTML和.text這兩個關鍵字

解法方案把$default參數的text改成content或其它名稱

    

撰寫本文時,此套件為v0.1.10版

未來官網文件、snackbak.js應該會陸續改版,改掉上述我提到的問題

如果未來我還記得此套件的話,到時候再修正此篇文章吧XD

本文的Live Demo

補充

上網使用關鍵字尋找「SnackBar」時,得留意Material Design for Bootstrap的作者fezvrasta也有另外寫一個SnackbarJS套件,兩者特性有點不太一樣,要小心別搞混XD