# 5.折叠窗与手风琴
在使用前,请一定记得引入jQuery.js与bootstrap.js文件
# 5.1 折叠窗基本使用
<p>
<!-- 通过a标签实现折叠窗触发 -->
<!-- 折叠窗的触发器上,需要配置几个属性 -->
<!-- data-toggle 属性,用于选择 切换 的事件——即以怎样的方式触发切换 -->
<!-- 可选值有:modal , popover , tooltips , collapse 等 -->
<!-- 折叠的效果,选择 collapse -->
<!-- 在a标签中实现折叠窗,href属性指定的是折叠的内容,常用id表示 -->
<a class="btn btn-primary" data-toggle="collapse" href="#collapseExample">
折叠触发器a
</a>
<!-- 通过按钮实现折叠窗触发 -->
<!-- 在按钮中,没法通过href属性指定折叠的内容,所以通过data-target来指定折叠的内容 -->
<button class="btn btn-primary" type="button" data-toggle="collapse" data-target="#collapseExample">
折叠触发器btn
</button>
</p>
<!-- 折叠的内容,需要配置 .collapse 类,来指明这是一个会被折叠的内容 -->
<!-- 同时需要配置id, id需要与触发器的 href的属性值 或 data-traget 的属性值 一致 -->
<div class="collapse" id="collapseExample">
<div class="card card-body">
折叠窗的内容
</div>
</div>
<!-- 也可以通过data-target指定多个目标 -->
<p>
<button data-toggle="collapse" data-target=".box1">折叠触发器btn</button>
</p>
<div class="collapse box1">
<div>内容1</div>
</div>
<div class="collapse box1">
<div>内容2</div>
</div>
<div class="collapse box1">
<div>内容3</div>
</div>
# 5.2 手风琴的基本使用
要实现手风琴,需要使用 .accordion 类 包裹住 整个内容
配合卡片组件(.card)使用效果良好
<div class="accordion" id="accordionExample">
<div class="card">
<div class="card-header" id="headingOne">
<h2 class="mb-0">
<!-- aria-expanded属性设置其默认展开与否 -->
<button class="btn btn-link btn-block text-left" type="button" data-toggle="collapse" data-target="#collapseOne" aria-expanded="true">
触发器1
</button>
</h2>
</div>
<div id="collapseOne" class="collapse show" aria-labelledby="headingOne" data-parent="#accordionExample">
<div class="card-body">
折叠内容1
</div>
</div>
</div>
<div class="card">
<div class="card-header" id="headingTwo">
<h2 class="mb-0">
<button class="btn btn-link btn-block text-left collapsed" type="button" data-toggle="collapse" data-target="#collapseTwo" >
触发器2
</button>
</h2>
</div>
<div id="collapseTwo" class="collapse" aria-labelledby="headingTwo" data-parent="#accordionExample">
<div class="card-body">
折叠内容2
</div>
</div>
</div>
<div class="card">
<div class="card-header" id="headingThree">
<h2 class="mb-0">
<button class="btn btn-link btn-block text-left collapsed" type="button" data-toggle="collapse" data-target="#collapseThree" >
触发器3
</button>
</h2>
</div>
<div id="collapseThree" class="collapse" aria-labelledby="headingThree" data-parent="#accordionExample">
<div class="card-body">
折叠内容3
</div>
</div>
</div>
</div>
<!-- 简练化 -->
<div class="according" id="boxParent">
<div>
<button data-target="#box1" data-toggle="collapse" aria-expended="true">触发器1</button>
<div class="collapse" id="box1" data-parent="#boxParent">内容1</div>
</div>
<div>
<button data-target="#box2" data-toggle="collpase">触发器2</button>
<div class="collapse" id="box2" data-parent="#boxParent">内容2</div>
</div>
<div>
<button data-target="#box3" data-toggle="collapse">触发器3</button>
<div class="collapse" id="box3" data-parent="#boxParent">内容3</div>
</div>
</div>
# 5.3 源码分析
原本看了一些……但是发现实在太长了,所以先停了了……
var NAME$3 = 'collapse';
var VERSION$3 = '4.6.0';
var DATA_KEY$3 = 'bs.collapse';
var EVENT_KEY$3 = "." + DATA_KEY$3;
var DATA_API_KEY$3 = '.data-api';
var JQUERY_NO_CONFLICT$3 = $__default['default'].fn[NAME$3];
var Default$1 = {
toggle: true,
parent: ''
};
var DefaultType$1 = {
toggle: 'boolean',
parent: '(string|element)'
};
var EVENT_SHOW = "show" + EVENT_KEY$3;
var EVENT_SHOWN = "shown" + EVENT_KEY$3;
var EVENT_HIDE = "hide" + EVENT_KEY$3;
var EVENT_HIDDEN = "hidden" + EVENT_KEY$3;
var EVENT_CLICK_DATA_API$3 = "click" + EVENT_KEY$3 + DATA_API_KEY$3;
var CLASS_NAME_SHOW$1 = 'show';
var CLASS_NAME_COLLAPSE = 'collapse';
var CLASS_NAME_COLLAPSING = 'collapsing';
var CLASS_NAME_COLLAPSED = 'collapsed';
var DIMENSION_WIDTH = 'width';
var DIMENSION_HEIGHT = 'height';
var SELECTOR_ACTIVES = '.show, .collapsing';
var SELECTOR_DATA_TOGGLE$1 = '[data-toggle="collapse"]';
var Collapse = /*#__PURE__*/ function() {
function Collapse(element, config) {
this._isTransitioning = false;
this._element = element;
this._config = this._getConfig(config);
// 两个选择器以保证a标签的href 和 data-target 都能获取到
this._triggerArray = [].slice.call(document.querySelectorAll("[data-toggle=\"collapse\"][href=\"#" +
element
.id + "\"]," + ("[data-toggle=\"collapse\"][data-target=\"#" + element.id + "\"]")));
// 获取所有折叠元素对象,以数组的形式存储
var toggleList = [].slice.call(document.querySelectorAll(SELECTOR_DATA_TOGGLE$1));
for (var i = 0, len = toggleList.length; i < len; i++) {
var elem = toggleList[i];
var selector = Util.getSelectorFromElement(elem);
var filterElement = [].slice.call(document.querySelectorAll(selector)).filter(function(foundElem) {
return foundElem === element;
});
if (selector !== null && filterElement.length > 0) {
this._selector = selector;
this._triggerArray.push(elem);
}
}
this._parent = this._config.parent ? this._getParent() : null;
if (!this._config.parent) {
this._addAriaAndCollapsedClass(this._element, this._triggerArray);
}
if (this._config.toggle) {
this.toggle();
}
} // Getters
var _proto = Collapse.prototype;
// Public
_proto.toggle = function toggle() {
if ($__default['default'](this._element).hasClass(CLASS_NAME_SHOW$1)) {
this.hide();
} else {
this.show();
}
};
_proto.show = function show() {
var _this = this;
if (this._isTransitioning || $__default['default'](this._element).hasClass(CLASS_NAME_SHOW$1)) {
return;
}
var actives;
var activesData;
if (this._parent) {
actives = [].slice.call(this._parent.querySelectorAll(SELECTOR_ACTIVES)).filter(function(elem) {
if (typeof _this._config.parent === 'string') {
return elem.getAttribute('data-parent') === _this._config.parent;
}
return elem.classList.contains(CLASS_NAME_COLLAPSE);
});
if (actives.length === 0) {
actives = null;
}
}
if (actives) {
activesData = $__default['default'](actives).not(this._selector).data(DATA_KEY$3);
if (activesData && activesData._isTransitioning) {
return;
}
}
var startEvent = $__default['default'].Event(EVENT_SHOW);
$__default['default'](this._element).trigger(startEvent);
if (startEvent.isDefaultPrevented()) {
return;
}
if (actives) {
Collapse._jQueryInterface.call($__default['default'](actives).not(this._selector), 'hide');
if (!activesData) {
$__default['default'](actives).data(DATA_KEY$3, null);
}
}
var dimension = this._getDimension();
$__default['default'](this._element).removeClass(CLASS_NAME_COLLAPSE).addClass(CLASS_NAME_COLLAPSING);
this._element.style[dimension] = 0;
if (this._triggerArray.length) {
$__default['default'](this._triggerArray).removeClass(CLASS_NAME_COLLAPSED).attr('aria-expanded',
true);
}
this.setTransitioning(true);
var complete = function complete() {
$__default['default'](_this._element).removeClass(CLASS_NAME_COLLAPSING).addClass(
CLASS_NAME_COLLAPSE + " " + CLASS_NAME_SHOW$1);
_this._element.style[dimension] = '';
_this.setTransitioning(false);
$__default['default'](_this._element).trigger(EVENT_SHOWN);
};
var capitalizedDimension = dimension[0].toUpperCase() + dimension.slice(1);
var scrollSize = "scroll" + capitalizedDimension;
var transitionDuration = Util.getTransitionDurationFromElement(this._element);
$__default['default'](this._element).one(Util.TRANSITION_END, complete).emulateTransitionEnd(
transitionDuration);
this._element.style[dimension] = this._element[scrollSize] + "px";
};
_proto.hide = function hide() {
var _this2 = this;
if (this._isTransitioning || !$__default['default'](this._element).hasClass(CLASS_NAME_SHOW$1)) {
return;
}
var startEvent = $__default['default'].Event(EVENT_HIDE);
$__default['default'](this._element).trigger(startEvent);
if (startEvent.isDefaultPrevented()) {
return;
}
var dimension = this._getDimension();
this._element.style[dimension] = this._element.getBoundingClientRect()[dimension] + "px";
Util.reflow(this._element);
$__default['default'](this._element).addClass(CLASS_NAME_COLLAPSING).removeClass(CLASS_NAME_COLLAPSE +
" " + CLASS_NAME_SHOW$1);
var triggerArrayLength = this._triggerArray.length;
if (triggerArrayLength > 0) {
for (var i = 0; i < triggerArrayLength; i++) {
var trigger = this._triggerArray[i];
var selector = Util.getSelectorFromElement(trigger);
if (selector !== null) {
var $elem = $__default['default']([].slice.call(document.querySelectorAll(selector)));
if (!$elem.hasClass(CLASS_NAME_SHOW$1)) {
$__default['default'](trigger).addClass(CLASS_NAME_COLLAPSED).attr('aria-expanded',
false);
}
}
}
}
this.setTransitioning(true);
var complete = function complete() {
_this2.setTransitioning(false);
$__default['default'](_this2._element).removeClass(CLASS_NAME_COLLAPSING).addClass(
CLASS_NAME_COLLAPSE).trigger(EVENT_HIDDEN);
};
this._element.style[dimension] = '';
var transitionDuration = Util.getTransitionDurationFromElement(this._element);
$__default['default'](this._element).one(Util.TRANSITION_END, complete).emulateTransitionEnd(
transitionDuration);
};
_proto.setTransitioning = function setTransitioning(isTransitioning) {
this._isTransitioning = isTransitioning;
};
_proto.dispose = function dispose() {
$__default['default'].removeData(this._element, DATA_KEY$3);
this._config = null;
this._parent = null;
this._element = null;
this._triggerArray = null;
this._isTransitioning = null;
} // Private
;
_proto._getConfig = function _getConfig(config) {
config = _extends({}, Default$1, config);
config.toggle = Boolean(config.toggle); // Coerce string values
Util.typeCheckConfig(NAME$3, config, DefaultType$1);
return config;
};
_proto._getDimension = function _getDimension() {
var hasWidth = $__default['default'](this._element).hasClass(DIMENSION_WIDTH);
return hasWidth ? DIMENSION_WIDTH : DIMENSION_HEIGHT;
};
_proto._getParent = function _getParent() {
var _this3 = this;
var parent;
if (Util.isElement(this._config.parent)) {
parent = this._config.parent; // It's a jQuery object
if (typeof this._config.parent.jquery !== 'undefined') {
parent = this._config.parent[0];
}
} else {
parent = document.querySelector(this._config.parent);
}
var selector = "[data-toggle=\"collapse\"][data-parent=\"" + this._config.parent + "\"]";
var children = [].slice.call(parent.querySelectorAll(selector));
$__default['default'](children).each(function(i, element) {
_this3._addAriaAndCollapsedClass(Collapse._getTargetFromElement(element), [element]);
});
return parent;
};
_proto._addAriaAndCollapsedClass = function _addAriaAndCollapsedClass(element, triggerArray) {
var isOpen = $__default['default'](element).hasClass(CLASS_NAME_SHOW$1);
if (triggerArray.length) {
$__default['default'](triggerArray).toggleClass(CLASS_NAME_COLLAPSED, !isOpen).attr(
'aria-expanded',
isOpen);
}
} // Static
;
Collapse._getTargetFromElement = function _getTargetFromElement(element) {
var selector = Util.getSelectorFromElement(element);
return selector ? document.querySelector(selector) : null;
};
Collapse._jQueryInterface = function _jQueryInterface(config) {
return this.each(function() {
var $element = $__default['default'](this);
var data = $element.data(DATA_KEY$3);
var _config = _extends({}, Default$1, $element.data(), typeof config === 'object' &&
config ? config : {});
if (!data && _config.toggle && typeof config === 'string' && /show|hide/.test(config)) {
_config.toggle = false;
}
if (!data) {
data = new Collapse(this, _config);
$element.data(DATA_KEY$3, data);
}
if (typeof config === 'string') {
if (typeof data[config] === 'undefined') {
throw new TypeError("No method named \"" + config + "\"");
}
data[config]();
}
});
};
_createClass(Collapse, null, [{
key: "VERSION",
get: function get() {
return VERSION$3;
}
}, {
key: "Default",
get: function get() {
return Default$1;
}
}]);
return Collapse;
}();