UNPKG

mdui

Version:

a CSS Framework based on material design

176 lines (175 loc) 5.47 kB
import $ from 'mdui.jq/es/$'; import extend from 'mdui.jq/es/functions/extend'; import 'mdui.jq/es/methods/addClass'; import 'mdui.jq/es/methods/children'; import 'mdui.jq/es/methods/each'; import 'mdui.jq/es/methods/eq'; import 'mdui.jq/es/methods/first'; import 'mdui.jq/es/methods/hasClass'; import 'mdui.jq/es/methods/height'; import 'mdui.jq/es/methods/is'; import 'mdui.jq/es/methods/on'; import 'mdui.jq/es/methods/parent'; import 'mdui.jq/es/methods/parents'; import 'mdui.jq/es/methods/removeClass'; import { isNumber } from 'mdui.jq/es/utils'; import '../../jq_extends/methods/reflow'; import '../../jq_extends/methods/transition'; import '../../jq_extends/methods/transitionEnd'; import { componentEvent } from '../../utils/componentEvent'; const DEFAULT_OPTIONS = { accordion: false, }; class CollapseAbstract { constructor(selector, options = {}) { /** * 配置参数 */ this.options = extend({}, DEFAULT_OPTIONS); // CSS 类名 const classPrefix = `mdui-${this.getNamespace()}-item`; this.classItem = classPrefix; this.classItemOpen = `${classPrefix}-open`; this.classHeader = `${classPrefix}-header`; this.classBody = `${classPrefix}-body`; this.$element = $(selector).first(); extend(this.options, options); this.bindEvent(); } /** * 绑定事件 */ bindEvent() { // eslint-disable-next-line @typescript-eslint/no-this-alias const that = this; // 点击 header 时,打开/关闭 item this.$element.on('click', `.${this.classHeader}`, function () { const $header = $(this); const $item = $header.parent(); const $items = that.getItems(); $items.each((_, item) => { if ($item.is(item)) { that.toggle(item); } }); }); // 点击关闭按钮时,关闭 item this.$element.on('click', `[mdui-${this.getNamespace()}-item-close]`, function () { const $target = $(this); const $item = $target.parents(`.${that.classItem}`).first(); that.close($item); }); } /** * 指定 item 是否处于打开状态 * @param $item */ isOpen($item) { return $item.hasClass(this.classItemOpen); } /** * 获取所有 item */ getItems() { return this.$element.children(`.${this.classItem}`); } /** * 获取指定 item * @param item */ getItem(item) { if (isNumber(item)) { return this.getItems().eq(item); } return $(item).first(); } /** * 触发组件事件 * @param name 事件名 * @param $item 事件触发的目标 item */ triggerEvent(name, $item) { componentEvent(name, this.getNamespace(), $item, this); } /** * 动画结束回调 * @param $content body 元素 * @param $item item 元素 */ transitionEnd($content, $item) { if (this.isOpen($item)) { $content.transition(0).height('auto').reflow().transition(''); this.triggerEvent('opened', $item); } else { $content.height(''); this.triggerEvent('closed', $item); } } /** * 打开指定面板项 * @param item 面板项的索引号、或 CSS 选择器、或 DOM 元素、或 JQ 对象 */ open(item) { const $item = this.getItem(item); if (this.isOpen($item)) { return; } // 关闭其他项 if (this.options.accordion) { this.$element.children(`.${this.classItemOpen}`).each((_, element) => { const $element = $(element); if (!$element.is($item)) { this.close($element); } }); } const $content = $item.children(`.${this.classBody}`); $content .height($content[0].scrollHeight) .transitionEnd(() => this.transitionEnd($content, $item)); this.triggerEvent('open', $item); $item.addClass(this.classItemOpen); } /** * 关闭指定面板项 * @param item 面板项的索引号、或 CSS 选择器、或 DOM 元素、或 JQ 对象 */ close(item) { const $item = this.getItem(item); if (!this.isOpen($item)) { return; } const $content = $item.children(`.${this.classBody}`); this.triggerEvent('close', $item); $item.removeClass(this.classItemOpen); $content .transition(0) .height($content[0].scrollHeight) .reflow() .transition('') .height('') .transitionEnd(() => this.transitionEnd($content, $item)); } /** * 切换指定面板项的打开状态 * @param item 面板项的索引号、或 CSS 选择器、或 DOM 元素、或 JQ 对象 */ toggle(item) { const $item = this.getItem(item); this.isOpen($item) ? this.close($item) : this.open($item); } /** * 打开所有面板项 */ openAll() { this.getItems().each((_, element) => this.open(element)); } /** * 关闭所有面板项 */ closeAll() { this.getItems().each((_, element) => this.close(element)); } } export { CollapseAbstract };