Bootstrap 4 中 Alerts 實現


Alert 的使用說明

http://v4-alpha.getbootstrap.com/components/alerts/

JavaScript behavior

Triggers

Enable dismissal of an alert via JavaScript:

$(".alert").alert()

Or with data attributes on a button within the alert, as demonstrated above:

<button type="button" class="close" data-dismiss="alert" aria-label="Close">
  <span aria-hidden="true">&times;</span>
</button>

Note that closing an alert will remove it from the DOM.

Methods

Method Description
$().alert() Makes an alert listen for click events on descendant elements which have the data-dismiss="alert" attribute. (Not necessary when using the data-api’s auto-initialization.)
$().alert('close') Closes an alert by removing it from the DOM. If the .fade and .in classes are present on the element, the alert will fade out before it is removed.
 
$(".alert").alert('close')

 

Events

Bootstrap’s alert plugin exposes a few events for hooking into alert functionality.

Event Description
close.bs.alert This event fires immediately when the close instance method is called.
closed.bs.alert This event is fired when the alert has been closed (will wait for CSS transitions to complete).
 
$('#myAlert').on('closed.bs.alert', function () {
  // do something…
})

獲取 bootstrap 4 

bootstrap v4 

源代碼分析

外層函數分析

從代碼的最外層來看,實際上是一個立即執行的函數,jQuery 就是我們熟悉的 jQuery 庫。

+function ($) {

} (jQuery);

對於在 function 之前使用 + 的用法,這里有詳細的說明:function與感嘆號

加上 Alert 之后,我們函數內部會成為嵌套的立即執行函數。

+function ($) {

    var Alert = (function ($) {

    })(jQuery);

} (jQuery);

有點問題,編碼風格不一致,這次里面使用了常見的括號方式來處理立即執行函數。

幾個輔助函數

創建類的函數 _createClass.

在 JavaScript 中,如何才能定義一個類呢?

類的作用在於同類的對象可以共享處理方法和數據,因此,在類中,必須有一個方式來共享所有同類對象所共享的成員,在 JavaSript 中,基本的方式是通過 function 的原型 prototype 來實現的。定義在 function 的 prototype 對象上的成員,可以被通過這個函數 new 出來的對象所共享。

所以,通常一個類是一個函數,我們把希望共享的成員定義在它的原型對象上。

同時,還可以定義靜態的成員,不需要通過對象實例來放問,可以直接通過類型來訪問,這些靜態成員可以直接定義在這個 function 對象上,沒錯,function 也是一個對象。

這樣的話,在創建一個類的時候,我們需要為這個函數定義實例成員和靜態成員,這就是 _createClass 這個函數的職責。

先看簡化版本,這個函數不是直接定義出來的,是調用一個匿名函數返回的。這又是一個立即執行函數。

var _createClass = (function () {

    return function () {
    
    }; 
})();

在它的內部定義了一個私有的函數,這個函數在外部不可調用。我們再擴展一下。這樣看的更加清楚一些。

var _createClass = (function () {

    // 內部的私有函數,外部不可調用.
    function defineProperties(target, props) {
      }
    }

    // 返回的函數,外部可以調用
    return function (Constructor, protoProps, staticProps) {
       defineProperties(Constructor.prototype, protoProps);
       return Constructor;
    };

})();

內部的這個 defineProperties 做什么呢?就是為目標對象定義屬性。屬性需要實現一些規范: Object.prototype, 下面的代碼就是實現規范的要求.

Object.prototype 屬性的屬性特性:
writable false
enumerable false
configurable false
// define prpperties on object.
function defineProperties(target, props) {
  for (var i = 0; i < props.length; i++) {
    var descriptor = props[i];
    descriptor.enumerable = descriptor.enumerable || false;
    descriptor.configurable = true;
    if ('value' in descriptor)
      descriptor.writable = true;
          
    // https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty
    Object.defineProperty(target, descriptor.key, descriptor);
  }
}

所以, 創建類型就是傳遞兩個分別描述實例成員和靜態成員的數組了.

_createClass 的全部代碼如下:

  var _createClass = (function () {

    // define prpperties on object.
    function defineProperties(target, props) {
      for (var i = 0; i < props.length; i++) {
        var descriptor = props[i];
        descriptor.enumerable = descriptor.enumerable || false;
        descriptor.configurable = true;
        if ('value' in descriptor)
          descriptor.writable = true;
          
        // https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty
        Object.defineProperty(target, descriptor.key, descriptor);
      }
    }

    // Constructor: target function
    // protoProps: prototype of function
    // staticProps: static properties
    return function (Constructor, protoProps, staticProps) {
      if (protoProps)
        defineProperties(Constructor.prototype, protoProps);
      if (staticProps)
        defineProperties(Constructor, staticProps);
      return Constructor;
    };
  })();

 Alert 定義

里面的 Alert 是一個變量,這個變量是一個內部函數 Alert 返回的. 而這個內部函數就是我們的 Alert 類定義. 可以看到在這個函數定義之后, 就被添加了我們類的成員.

var Alert = (function ($) {
    function Alert(element) {
        _classCallCheck(this, Alert);

        this._element = element;
    }

  _createClass(Alert, [{......}]);

  return Alert;
})();

 再看剩下處理內容.

在 document 上注冊了一個名為 "click.bs.alert.data-api" 的事件處理程序, 在 jQuery 中吧on 函數的定義如下:

.on( events [, selector ] [, data ], handler )

see also: http://api.jquery.com/on/

第一個參數是事件名稱,有可選的選擇器,還有事件處理程序.

$(document).on(Event.CLICK_DATA_API, Selector.DISMISS, Alert._handleDismiss(new Alert()));

 

最后, 是適配到 jQuery 的原型中, 以便直接通過 jQuery 對象實例進行處理. 其中的工作NAME 這里就是 alert 了.

/**
* ------------------------------------------------------------------------
* jQuery
* ------------------------------------------------------------------------
*/

$.fn[NAME] = Alert._jQueryInterface;
$.fn[NAME].Constructor = Alert;
$.fn[NAME].noConflict = function () {
    $.fn[NAME] = JQUERY_NO_CONFLICT;
    return Alert._jQueryInterface;
};

return Alert;

 

這里的工作_jQueryInterface 就是一個函數.

function _jQueryInterface(config) {
    return this.each(function () {
        var $element = $(this);
        var data = $element.data(DATA_KEY);

        if (!data) {
            data = new Alert(this);
            $element.data(DATA_KEY, data);
        }

        if (config === 'close') {
            data[config](this);
        }
    });
}

 

注冊事件處理函數

// Event.CLICK_DATA_API: click.bs.alert.data-api
// Selector.DISMISS: [data-dismiss="alert"]
// register a event handler
$(document).on(Event.CLICK_DATA_API, Selector.DISMISS, Alert._handleDismiss(new Alert()));

 注意,這里的事件名稱並不是通常的 click, 而是 click.bs.alert.data-api,這里涉及到 jQuery 的事件命名空間問題,可以到這里參考 jQuery 的文檔:http://api.jquery.com/on/#event-names

作用就是我們可以在取消某些事件處理注冊的時候,不會影響其它已經注冊的事件處理程序。

目標選擇器則為:[data-dismiss="alert"] ,這正是 bootstrap 所要求的按鈕必須擁有的屬性。

 

 全部的 Alert 代碼.

/**
 * --------------------------------------------------------------------------
 * Bootstrap (v4.0.0-alpha.2): alert.js
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
 * --------------------------------------------------------------------------
 */

  var Alert = (function ($) {

    /**
     * ------------------------------------------------------------------------
     * Constants
     * ------------------------------------------------------------------------
     */

    var NAME = 'alert';
    var VERSION = '4.0.0-alpha';
    var DATA_KEY = 'bs.alert';
    var EVENT_KEY = '.' + DATA_KEY;
    var DATA_API_KEY = '.data-api';
    var JQUERY_NO_CONFLICT = $.fn[NAME];
    var TRANSITION_DURATION = 150;

    var Selector = {
      DISMISS: '[data-dismiss="alert"]'
    };

    var Event = {
      CLOSE: 'close' + EVENT_KEY,
      CLOSED: 'closed' + EVENT_KEY,
      CLICK_DATA_API: 'click' + EVENT_KEY + DATA_API_KEY
    };

    var ClassName = {
      ALERT: 'alert',
      FADE: 'fade',
      IN: 'in'
    };

    /**
     * ------------------------------------------------------------------------
     * Class Definition
     * ------------------------------------------------------------------------
     */

    var Alert = (function () {
      
      // class define
      function Alert(element) {
        _classCallCheck(this, Alert);

        this._element = element;
      }

      /**
       * ------------------------------------------------------------------------
       * Data Api implementation
       * ------------------------------------------------------------------------
       */

      // getters

      _createClass(Alert, [{
        key: 'close',

        // public

        value: function close(element) {
          element = element || this._element;

          var rootElement = this._getRootElement(element);
          var customEvent = this._triggerCloseEvent(rootElement);

          if (customEvent.isDefaultPrevented()) {
            return;
          }

          this._removeElement(rootElement);
        }
      }, {
          key: 'dispose',
          value: function dispose() {
            $.removeData(this._element, DATA_KEY);
            this._element = null;
          }

          // private

        }, {
          key: '_getRootElement',
          value: function _getRootElement(element) {
            var selector = Util.getSelectorFromElement(element);
            var parent = false;

            if (selector) {
              parent = $(selector)[0];
            }

            if (!parent) {
              parent = $(element).closest('.' + ClassName.ALERT)[0];
            }

            return parent;
          }
        }, {
          key: '_triggerCloseEvent',
          value: function _triggerCloseEvent(element) {
            var closeEvent = $.Event(Event.CLOSE);

            $(element).trigger(closeEvent);
            return closeEvent;
          }
        }, {
          key: '_removeElement',
          value: function _removeElement(element) {
            $(element).removeClass(ClassName.IN);

            if (!Util.supportsTransitionEnd() || !$(element).hasClass(ClassName.FADE)) {
              this._destroyElement(element);
              return;
            }

            $(element).one(Util.TRANSITION_END, $.proxy(this._destroyElement, this, element)).emulateTransitionEnd(TRANSITION_DURATION);
          }
        }, {
          key: '_destroyElement',
          value: function _destroyElement(element) {
            $(element).detach().trigger(Event.CLOSED).remove();
          }

          // static

        }], [{
          key: '_jQueryInterface',
          value: function _jQueryInterface(config) {
            return this.each(function () {
              var $element = $(this);
              var data = $element.data(DATA_KEY);

              if (!data) {
                data = new Alert(this);
                $element.data(DATA_KEY, data);
              }

              if (config === 'close') {
                data[config](this);
              }
            });
          }
        }, {
            key: '_handleDismiss',
            value: function _handleDismiss(alertInstance) {
              return function (event) {
                if (event) {
                  event.preventDefault();
                }

                alertInstance.close(this);
              };
            }
          }, {
            key: 'VERSION',
            get: function get() {
              return VERSION;
            }
          }]);

      return Alert;
    })();

    $(document).on(Event.CLICK_DATA_API, Selector.DISMISS, Alert._handleDismiss(new Alert()));

    /**
     * ------------------------------------------------------------------------
     * jQuery
     * ------------------------------------------------------------------------
     */

    $.fn[NAME] = Alert._jQueryInterface;
    $.fn[NAME].Constructor = Alert;
    $.fn[NAME].noConflict = function () {
      $.fn[NAME] = JQUERY_NO_CONFLICT;
      return Alert._jQueryInterface;
    };

    return Alert;
  })(jQuery);
  
} (jQuery);

 使用的樣式

.alert {
  padding: 15px;
  margin-bottom: 1rem;
  border: 1px solid transparent;
  border-radius: .25rem;
}

.alert > p,
.alert > ul {
  margin-bottom: 0;
}

.alert > p + p {
  margin-top: 5px;
}

.alert-heading {
  color: inherit;
}

.alert-link {
  font-weight: bold;
}

.alert-dismissible {
  padding-right: 35px;
}

.alert-dismissible .close {
  position: relative;
  top: -2px;
  right: -21px;
  color: inherit;
}

.alert-success {
  color: #3c763d;
  background-color: #dff0d8;
  border-color: #d0e9c6;
}

.alert-success hr {
  border-top-color: #c1e2b3;
}

.alert-success .alert-link {
  color: #2b542c;
}

.alert-info {
  color: #31708f;
  background-color: #d9edf7;
  border-color: #bcdff1;
}

.alert-info hr {
  border-top-color: #a6d5ec;
}

.alert-info .alert-link {
  color: #245269;
}

.alert-warning {
  color: #8a6d3b;
  background-color: #fcf8e3;
  border-color: #faf2cc;
}

.alert-warning hr {
  border-top-color: #f7ecb5;
}

.alert-warning .alert-link {
  color: #66512c;
}

.alert-danger {
  color: #a94442;
  background-color: #f2dede;
  border-color: #ebcccc;
}

.alert-danger hr {
  border-top-color: #e4b9b9;
}

.alert-danger .alert-link {
  color: #843534;
}

 

 待續......

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM