FineUIMvc隨筆(7)擴充套件通知對話方塊(顯示多個不重疊)

三生石上(FineUI控制元件)發表於2017-04-13

宣告:FineUIMvc(基礎版)是免費軟體,本系列文章適用於基礎版。

這篇文章我們將改造 FineUIMvc 預設的通知對話方塊,使得同時顯示多個也不會重疊。並提前出一個公共的JS檔案,供大家使用。

FineUIMvc 的通知對話方塊

FineUIMvc預設的通知對話方塊透過 F.notify 來顯示,可以在頁面上的 9 個位置顯示,分別對應於屬性:

  1. PosotionX = Left,  PositionY = Top
  2. PosotionX = Left,  PositionY = Center
  3. PosotionX = Left,  PositionY = Bottom
  4. PosotionX = Center,  PositionY = Top
  5. PosotionX = Center,  PositionY = Center
  6. PosotionX = Center,  PositionY = Bottom
  7. PosotionX = Right,  PositionY = Top
  8. PosotionX = Right,  PositionY = Center
  9. PosotionX = Right,  PositionY = Bottom

我們有專門的示例頁面來演示相應的效果:

http://fineui.com/demo_mvc/#/demo_mvc/Message/Notify

 

美中不足的時,如果同時有多個通知對話方塊時,就會出現重疊,如下所示:

 

自定義通知對話方塊分組

為了解決這個問題,我們需要對 F.notify 進行一個簡單的封裝,得到的效果如下圖所示:

呼叫這個封裝好的函式非常簡單,來看下這個頁面的實現程式碼:

@(F.Button()
    .Text("彈出通知對話方塊(多次點選)")
    .ID("btnOperation1")
    .Listener("click", "onOperation1Click")
)
<script src="~/res/js/notify_group.js"></script>
<script type="text/javascript">

    var _orderNumber = 0;

    function onOperation1Click(event) {
        // 建立一個訊息對話方塊例項
        var displayTime = 2000 + Math.random() * 10000;

        var allMessageIcons = ['information', 'warning', 'question', 'error', 'success'];
        showNotifyGroup({
            message: '這是第 <strong>' + _orderNumber + '</strong> 條提示資訊,顯示' + Math.floor(displayTime / 1000) + '秒',
            messageIcon: allMessageIcons[_orderNumber % allMessageIcons.length],
            header: false,
            displayMilliseconds: displayTime
        });

        _orderNumber++;
    }

</script>

這裡面實際執行的函式就是 showNotifyGroup,需要傳入的引數如下:

1. message:顯示的訊息正文

2. messgeIcon:訊息正文前面的圖示

3. displayMilliseconds:顯示的毫秒數(然後會自動消失)

 

其實,我們可以傳入 F.notify 的任何引數,因為 showNotifyGroup 內部也是對 F.notify 的呼叫,只不過做了一定的擴充套件。

 

下面就來看下 showNotifyGroup 函式的具體實現:

// 通知對話方塊分組
(function () {

    // _notifySpace: 訊息框之間的間距
    // _notifies: 存放當前正在顯示的對話方塊列表
    var _orderNumber = 1, _notifySpace = 5, _notifies = [];

    // 對話方塊關閉處理函式
    function onNotifyHide() {
        var notify = this;
        var notifyHeight = notify.el.outerHeight(true) + _notifySpace;
        var notifyIndex = $.inArray(notify, _notifies);
        _notifies.splice(notifyIndex, 1);

        var count = _notifies.length;
        if (count) {
            for (var i = notifyIndex; i < count; i++) {
                var item = _notifies[i];
                item.top -= notifyHeight;
                item.el.animate({
                    'top': item.top
                });
            }

            // 按照 notify.top 重新排序
            _notifies.sort(function (a, b) {
                return a.top - b.top;
            });
        }
    }


    // 獲取對話方塊元素的top屬性
    function calcNotifyTop() {
        var top = _notifySpace;
        if (_notifies.length) {
            var lastNotify = _notifies[_notifies.length - 1];
            top += lastNotify.top + lastNotify.el.outerHeight(true);
        }
        return top;
    }

    // 公開方法
    window.showNotifyGroup = function (options) {
        // 建立一個訊息對話方塊例項
        $.extend(options, {
            top: calcNotifyTop(),
            positionX: 'right',
            listeners: {
                hide: onNotifyHide
            }
        });

        _notifies.push(F.notify(options));
    }


})();

 

首先看下公開的 showNotifyGroup 方法的實現,需要傳入 F.notify 的有三個引數:

1. top:訊息框左上角的垂直座標,由於最新的在最後面顯示,所以每次都要計算這個位置

2. posotionX:固定為 right,也就是在頁面右側顯示

3. hide:訊息框隱藏時的處理函式,裡面主要是 3 個處理:

------3.1:從訊息框佇列中刪除需要隱藏的訊息框

------3.2:改變正在顯示的所有訊息框的 top 屬性

------3.3:按照 top 由小到大的順序排序

 

自定義通知對話方塊分組(最新的顯示在最上方)

上面實現的效果是最新的顯示在最下方,程式碼還比較簡潔。而如果要求最新的顯示在最上方,則面臨對動畫效果的控制:

1. 顯示新訊息框時,需要將現有的所有訊息框下移,並且等到大家都完成下移動作後,再顯示新訊息框

2. 顯示新訊息框時,有可能正在進行下移動畫效果,並且上一個訊息框還沒顯示(正在等動畫完成),此時需要立即終止所有動畫,並顯示上一個訊息框,之後再處理新的訊息框

3. 某個訊息框隱藏時,也有可能正在進行下移動畫,此時也要做相同的處理

 

所以,雖然封裝的程式碼邏輯複雜了,不過呼叫方法依然沒變,效果也是很讚的:

 

這個示例的呼叫程式碼很簡單,和上例相比,只多了一個 true 的引數:

<script src="~/res/js/notify_group.js"></script>
<script type="text/javascript">

    var _orderNumber = 0;

    function onOperation1Click(event) {
        // 建立一個訊息對話方塊例項
        var displayTime = 2000 + Math.random() * 10000;

        var allMessageIcons = ['information', 'warning', 'question', 'error', 'success'];
        showNotifyGroup({
            message: '這是第 <strong>' + _orderNumber + '</strong> 條提示資訊,顯示' + Math.floor(displayTime / 1000) + '秒',
            messageIcon: allMessageIcons[_orderNumber % allMessageIcons.length],
            header: false,
            displayMilliseconds: displayTime
        }, true);

        _orderNumber++;
    }

</script>

 

 

現在來看下完整的 notify_group.js 的程式碼:

// 通知對話方塊分組
(function () {

    // _notifySpace: 訊息框之間的間距
    // _notifies: 存放當前正在顯示的對話方塊列表
    var _orderNumber = 1, _notifySpace = 5, _notifies = [];

    // 對話方塊關閉處理函式
    function onNotifyHide() {
        // 先清空之前尚未完成的動畫
        clearNotifiesAnimation();

        var notify = this;
        var notifyHeight = notify.el.outerHeight(true) + _notifySpace;
        var notifyIndex = $.inArray(notify, _notifies);
        _notifies.splice(notifyIndex, 1);

        var count = _notifies.length;
        if (count) {
            for (var i = notifyIndex; i < count; i++) {
                var item = _notifies[i];
                item.top -= notifyHeight;
                item.el.animate({
                    'top': item.top
                });
            }

            // 按照 notify.top 重新排序
            _notifies.sort(function (a, b) {
                return a.top - b.top;
            });
        }
    }

    // 所有對話方塊下移
    function moveNotifiesDown(newNotify, fn) {
        // 先清空之前尚未完成的動畫
        clearNotifiesAnimation();

        var count = _notifies.length, finished = 0;
        if (!count) {
            fn.apply(window);
            return;
        }

        var notifyHeight = newNotify.el.outerHeight(true) + _notifySpace;
        for (var i = 0; i < count; i++) {
            var item = _notifies[i];
            item.top += notifyHeight;
            item.el.animate({
                'top': item.top
            }, function () {
                // 動畫完成後執行的函式
                finished++;

                if (finished >= count) {
                    fn.apply(window);
                }
            });
        }
    }

    // 停止動畫,並回撥
    function clearNotifiesAnimation() {
        var count = _notifies.length;
        if (count) {
            for (var i = 0; i < count; i++) {
                var item = _notifies[i];
                var itemEl = item.el;
                if (itemEl.is(":animated")) {
                    itemEl.stop(false, true);
                }
            }
        }
    }

    // 獲取對話方塊元素的top屬性
    function calcNotifyTop() {
        var top = _notifySpace;
        if (_notifies.length) {
            var lastNotify = _notifies[_notifies.length - 1];
            top += lastNotify.top + lastNotify.el.outerHeight(true);
        }
        return top;
    }

    // 公開方法
    window.showNotifyGroup = function (options, newestOnTop) {
        // 建立一個訊息對話方塊例項
        $.extend(options, {
            positionX: 'right',
            listeners: {
                hide: onNotifyHide
            }
        });

        if (newestOnTop) {
            // 最新的顯示在最上方,需要先隱藏,等 moveNotifiesDown 之後再顯示
            options.hidden = true;
            options.top = _notifySpace;
        } else {
            options.top = calcNotifyTop();
        }

        var notify = F.notify(options);

        if (newestOnTop) {
            moveNotifiesDown(notify, function () {
                notify.show();
            });
            _notifies.splice(0, 0, notify);
        } else {
            _notifies.push(notify);
        }
    }


})();

 

如果你也想要這樣的效果,很簡單,把 notify_group.js 丟到你的專案中,直接呼叫 showNotifyGroup 函式即可!

 

小結

雖然本篇講的是 FineUIMvc ,其實是對內部 JavaScript 程式碼的一個簡單擴充套件和封裝,由此可見 FineUIMvc 前端庫的靈活性。我們可以直接把 notify_group.js 丟到專案中,呼叫 showNotifyGroup 函式即可實現上述效果。你也可以自行擴充套件來在頁面的不同地方顯示通知對話方塊,實現更復雜的動畫效果。

 

《FineUIMvc隨筆》目錄:http://www.cnblogs.com/sanshi/p/6473592.html 

 

相關文章