
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:;
} .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;
}
待续......