UNPKG

rabbit-simple-ui

Version:

A simple UI component library based on JavaScript

370 lines (301 loc) 11.9 kB
import PREFIX from '../prefix'; import { $el, bind, createElem, getBooleanTypeAttr, getStrTypeAttr, removeAttrs, setCss, setHtml } from '../../dom-utils'; import { CssTransition, moreThanOneNode, Scrollable } from '../../mixins'; import { type, validComps } from '../../utils'; interface DrawerEvents { onClose?: () => void; } interface Config { config( el: string ): { title: string; visable: boolean; events: ({ onClose }: DrawerEvents) => void; }; } class Drawer implements Config { readonly VERSION: string; readonly COMPONENTS: NodeListOf<Element>; constructor() { this.VERSION = 'v1.1.1'; this.COMPONENTS = $el('r-drawer', { all: true }); this._create(this.COMPONENTS); } public config( el: string ): { title: string; visable: boolean; events: ({ onClose }: DrawerEvents) => void; } { const target = $el(el); validComps(target, 'drawer'); const { _handleVisable, _attrs } = Drawer.prototype; const DrawerMask = target.querySelector(`.${PREFIX.drawer}-mask`); const DrawerWrap = target.querySelector(`.${PREFIX.drawer}-wrap`); const _Drawer = target.querySelector(`.${PREFIX.drawer}`); const DrawerTitle = target.querySelector(`.${PREFIX.drawer}-header-inner`); const DrawerClose = target.querySelector(`.${PREFIX.drawer}-close`); return { get title() { return setHtml(DrawerTitle); }, set title(newVal: string) { if (!type.isStr(newVal)) return; setHtml(DrawerTitle, newVal); }, get visable() { return false; }, set visable(newVal: boolean) { if (!type.isBol(newVal)) return; _handleVisable(newVal, target, [DrawerMask, DrawerWrap, _Drawer]); }, events({ onClose }) { // v1.0.1 改用on事件绑定,防止触发回调事件的次数随着每次点击而不断的重复叠加 if (DrawerClose) DrawerClose.onclick = () => onClose && type.isFn(onClose); if (_attrs(target).maskClosable === 'true') DrawerWrap.onclick = () => onClose && type.isFn(onClose); } }; } private _create(COMPONENTS: NodeListOf<Element>): void { COMPONENTS.forEach((node) => { this._createDrawerNodes(node); setCss(node, 'display', 'block'); removeAttrs(node, [ 'title', 'width', 'height', 'mask', 'visible', 'closable', 'scrollable', 'lock-scroll' ]); }); } private _createDrawerNodes(node: Element): void { const DrawerMask = createElem('div'); const DrawerWrap = createElem('div'); const Drawer = createElem('div'); const DrawerContent = createElem('div'); const DrawerClose = createElem('a'); const DrawerHeader = createElem('div'); const DrawerHeaderInner = createElem('div'); const DrawerBody = createElem('div'); this._setCls([ DrawerMask, DrawerWrap, Drawer, DrawerContent, DrawerClose, DrawerHeader, DrawerHeaderInner, DrawerBody ]); this._setSize(node, Drawer); this._setPlacement(node, Drawer); this._setOpenInContainer(node, DrawerMask, DrawerWrap, Drawer); this._initVisible(node, DrawerMask, DrawerWrap, Drawer); this._handleClose(node, [DrawerMask, DrawerWrap, Drawer], DrawerClose); DrawerWrap.appendChild(Drawer); Drawer.appendChild(DrawerContent); this._setClosable(node, DrawerContent, DrawerClose); this._setHeader(node, DrawerContent, DrawerHeader, DrawerHeaderInner); DrawerContent.appendChild(DrawerBody); this._setBodyContent(node, DrawerBody); this._setMask(node, DrawerMask, DrawerWrap, DrawerContent); node.appendChild(DrawerWrap); } private _setCls(elms: HTMLElement[]): void { const elmsCls = [ `${PREFIX.drawer}-mask`, `${PREFIX.drawer}-wrap`, `${PREFIX.drawer}`, `${PREFIX.drawer}-content`, `${PREFIX.drawer}-close`, `${PREFIX.drawer}-header`, `${PREFIX.drawer}-header-inner`, `${PREFIX.drawer}-body` ]; let i = 0; const { length } = elms; for (; i < length; i++) { const elm = elms[i]; elm.className = elmsCls[i]; } } private _setSize(parent: Element, children: HTMLElement): void { const { width, height, placement } = this._attrs(parent); if (placement === 'top' || placement === 'bottom') { setCss(children, 'height', height); } else if (placement === 'left' || placement === 'right') { children.style.width = width; setCss(children, 'width', width); } } private _setPlacement(parent: Element, children: HTMLElement): void { const { placement } = this._attrs(parent); children.classList.add(`${PREFIX.drawer}-${placement}`); } private _setOpenInContainer( parent: Element, drawerMask: HTMLElement, drawerWrap: HTMLElement, drawer: HTMLElement ): void { const { inner } = this._attrs(parent); if (!inner) return; drawerMask.classList.add(`${PREFIX.drawer}-mask-inner`); drawerWrap.classList.add(`${PREFIX.drawer}-wrap-inner`); drawer.classList.add(`${PREFIX.drawer}-inner`); } private _setMask( parent: Element, drawerMask: HTMLElement, drawerWrap: HTMLElement, drawerContent: HTMLElement ): void { let { mask } = this._attrs(parent); if (parent.getAttribute('mask') == null) mask = true; if (!mask) { drawerWrap.classList.add(`${PREFIX.drawer}-no-mask`); drawerContent.classList.add(`${PREFIX.drawer}-content-no-mask`); return; } parent.appendChild(drawerMask); } private _setClosable(parent: Element, children: HTMLElement, drawerClose: HTMLElement): void { const { closable } = this._attrs(parent); if (!closable) return; setHtml(drawerClose, `<i class="${PREFIX.icon} ${PREFIX.icon}-ios-close"></i>`); children.appendChild(drawerClose); } private _setHeader( parent: Element, drawerContent: HTMLElement, drawerHeader: HTMLElement, drawerTitle: HTMLElement ): void { const { title } = this._attrs(parent); if (!title) { drawerContent.parentElement?.classList.add(`${PREFIX.drawer}-no-header`); return; } setHtml(drawerTitle, title); drawerHeader.appendChild(drawerTitle); drawerContent.appendChild(drawerHeader); } private _setBodyContent(parent: Element, children: HTMLElement): void { // v1.1.1 增加占位节点的组成数量判断 if (moreThanOneNode(parent)) return; const placeholderNode = parent.firstElementChild; if (placeholderNode) children.appendChild(placeholderNode); } private _initVisible( parent: Element, drawerMask: HTMLElement, drawerWrap: HTMLElement, drawer: HTMLElement ): void { const { visible } = this._attrs(parent); // @ts-ignore parent.dataset.drawerVisable = `${visible}`; if (visible) return; drawerWrap.classList.add(`${PREFIX.drawer}-hidden`); setCss(drawerMask, 'display', 'none'); setCss(drawer, 'display', 'none'); } private _handleVisable(visable: boolean, target: Element, children: Element[]): void { const { _show, _hide } = Drawer.prototype; visable ? _show(target, children) : _hide(target, children); } private _handleClose(parent: Element, hiddenElm: Element[], triggerElm: HTMLElement): void { const { _hide } = Drawer.prototype; // triggerElm 表示右上角关闭按钮 bind(triggerElm, 'click', () => _hide(parent, hiddenElm)); bind(hiddenElm[1], 'click', () => _hide(parent, hiddenElm)); bind(hiddenElm[2], 'click', (e: any) => e.stopPropagation()); } private _show(parent: Element, showElm: Element[]): void { const { _attrs } = Drawer.prototype; const { inner, placement, scrollable } = _attrs(parent); let { lockScroll } = _attrs(parent); !parent.getAttribute('lock-scroll') ? (lockScroll = true) : lockScroll; // 设置为在当前 dom 里打开则不隐藏 body 滚动条 if (!inner) Scrollable({ scroll: scrollable, lock: lockScroll }); // @ts-ignore // 设置当前为显示状态 parent.dataset.drawerVisable = 'true'; // showElm[0] 表示遮盖层 // showElm[1] 表示抽屉的父容器wrap // showElm[2] 表示抽屉主体 showElm[1].classList.contains(`${PREFIX.drawer}-hidden`) && showElm[1].classList.remove(`${PREFIX.drawer}-hidden`); CssTransition(showElm[0], { inOrOut: 'in', enterCls: 'rab-fade-in', rmCls: true, timeout: 250 }); CssTransition(showElm[2], { inOrOut: 'in', enterCls: `${PREFIX.drawer}-${placement}-move-enter`, rmCls: true, timeout: 550 }); } private _hide(parent: Element, hiddenElm: Element[]): void { const { placement } = Drawer.prototype._attrs(parent); // @ts-ignore // 设置为隐藏状态 parent.dataset.drawerVisable = 'false'; // hiddenElm[0] 表示遮盖层 // hiddenElm[1] 表示抽屉的父容器wrap // hiddenElm[2] 表示抽屉主体 CssTransition(hiddenElm[0], { inOrOut: 'out', leaveCls: 'rab-fade-out', rmCls: true, timeout: 250 }); CssTransition(hiddenElm[2], { inOrOut: 'out', leaveCls: `${PREFIX.drawer}-${placement}-move-leave`, rmCls: true, timeout: 490 }); setTimeout(() => { hiddenElm[1].classList.add(`${PREFIX.drawer}-hidden`); setCss(hiddenElm[2], 'display', 'none'); Scrollable({ scroll: true, lock: true, node: parent, tagName: 'drawer' }); }, 490); } private _attrs(node: Element) { return { title: getStrTypeAttr(node, 'title', ''), width: getStrTypeAttr(node, 'width', '256px'), height: getStrTypeAttr(node, 'height', '256px'), placement: getStrTypeAttr(node, 'placement', 'right'), mask: getBooleanTypeAttr(node, 'mask'), inner: getBooleanTypeAttr(node, 'inner'), visible: getBooleanTypeAttr(node, 'visible'), closable: getBooleanTypeAttr(node, 'closable'), scrollable: getBooleanTypeAttr(node, 'scrollable'), lockScroll: getBooleanTypeAttr(node, 'lock-scroll'), maskClosable: getStrTypeAttr(node, 'mask-closable', 'true') }; } } export default Drawer;