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">×</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
源代码分析
外层函数分析
从代码的最外层来看,实际上是一个立即执行的函数,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; }
待续......