UNPKG

rabbit-simple-ui

Version:

A simple UI component library based on JavaScript

277 lines (229 loc) 8.56 kB
import { warn } from '../../mixins'; import { $el, createElem, removeAttrs, setCss, setHtml, setText } from '../../dom-utils'; import { type, validComps } from '../../utils'; import PREFIX from '../prefix'; interface Config { config( el: string ): { count: number; text: string; dot: boolean; }; } class Badge implements Config { readonly VERSION: string; readonly COMPONENTS: NodeListOf<Element>; constructor() { this.VERSION = 'v1.0'; this.COMPONENTS = $el('r-badge', { all: true }); this._create(this.COMPONENTS); } public config( el: string ): { count: number; text: string; dot: boolean; } { const target = $el(el); validComps(target, 'badge'); const countContainer = target.querySelector(`.${PREFIX.badge}-count`); const dotContainer = target.querySelector(`.${PREFIX.badge}-dot`); const { _getMaxCount, _showZero, _setMaxCount } = Badge.prototype; const maxCount = _getMaxCount(target); const showZero = _showZero(target); return { get count() { return countContainer?.textContent; }, set count(newVal: number) { if (countContainer && type.isNum(newVal)) { if (newVal > maxCount) { _setMaxCount(countContainer, maxCount); } else { setText(countContainer, `${newVal}`); if (newVal <= 0 && !showZero) { setCss(countContainer, 'display', 'none'); } else { setCss(countContainer, 'display', ''); } } } else { warn(`The count value of this badge cannot be set --> "${el}"`); } }, get text() { return countContainer?.textContent; }, set text(newVal: string) { if (!type.isStr(newVal)) { warn(`The text value of this badge cannot be set --> "${el}"`); return; } setText(countContainer, newVal); }, get dot() { return dotContainer; }, set dot(newVal: boolean) { if (!dotContainer) { warn(`Unable to set this badge to dot --> "${el}"`); return; } if (type.isBol(newVal) && newVal) { setCss(dotContainer, 'display', ''); } else { setCss(dotContainer, 'display', 'none'); } } }; } private _create(COMPONENTS: NodeListOf<Element>): void { COMPONENTS.forEach((node) => { this._setCount(node); this._setStatusWithColor(node); removeAttrs(node, [ 'count', 'text', 'status', 'color', 'show-zero', 'max-count', 'dot' ]); }); } private _setCount(node: Element): void { const count = this._getCount(node); const maxCount = this._getMaxCount(node); const BadgeCount = createElem('sup'); BadgeCount.className = `${PREFIX.badge}-count`; if (count || count === 0) { // 显示的数字大于maxCount时,显示${maxCount}+ if (count > maxCount) { this._setMaxCount(BadgeCount, maxCount); } else { // 数字为 0 时隐藏或者展示 Badge if (count <= 0 && !this._showZero(node)) { setCss(BadgeCount, 'display', 'none'); } else { setText(BadgeCount, `${count}`); } } this._setDot(node, BadgeCount); } if (!this._getStatus(node) && !this._getColor(node)) { node.appendChild(BadgeCount); // 状态点外观不需要设置为独立展示 this._setAlone(BadgeCount); } this._setText(node, BadgeCount); this._setOffset(node, BadgeCount); } private _setMaxCount(node: Element, maxCount: number): void { setText(node, `${maxCount}+`); } private _setDot(node: Element, children: HTMLElement): void { if (!this._showDot(node)) return; // 设置为小红点则不显示任何计数内容 setHtml(children, ''); setCss(children, 'display', ''); children.className = `${PREFIX.badge}-dot`; } private _setText(parent: Element, children: HTMLElement): void { // 区分与标签属性 status 或 color 配合的 text 属性 if (!this._getStatus(parent) && !this._getColor(parent)) { const text = this._getText(parent); if (text) { setCss(children, 'display', ''); setText(children, text); } } } private _setAlone(children: Element): void { if (!children.previousElementSibling) { children.classList.add(`${PREFIX.badge}-count-alone`); } } private _setOffset(parent: Element, children: HTMLElement) { const offset = this._getOffset(parent); setCss(children, 'marginTop', `${offset?.x}px`); setCss(children, 'marginRight', `${offset?.y}px`); } private _setStatusWithColor(node: Element): void { const status = this._getStatus(node); const color = this._getColor(node); const text = this._getText(node); if (!status && !color) return; const BadgeStatusDot = createElem('span'); const BadgeStatusText = createElem('span'); if ((text && status) || (text && color)) setText(BadgeStatusText, text); let statusCls: string; let colorCls = ''; status ? (statusCls = `${PREFIX.badge}-status-${status}`) : (statusCls = ''); // 设置更多预设的状态点颜色,或者自定义颜色 const colorType = [ 'blue', 'green', 'red', 'yellow', 'magenta', 'volcano', 'orange', 'gold', 'lime', 'cyan', 'geekblue', 'purple' ]; if (colorType.includes(color)) { colorCls = `${PREFIX.badge}-status-${color}`; } else { setCss(BadgeStatusDot, 'backgroundColor', color); } BadgeStatusDot.className = `${PREFIX.badge}-status-dot ${statusCls} ${colorCls}`; BadgeStatusText.className = `${PREFIX.badge}-status-text`; node.append(BadgeStatusDot, BadgeStatusText); } private _getCount(node: Element) { return Number(node.getAttribute('count')); } private _getMaxCount(node: Element): number { return Number(node.getAttribute('max-count')) || 99; } private _getOffset( node: Element ): | { x: any | number; y: any | number; } | undefined { // 转为真实数组,如果赋值是 offset = ['0','1'] 这样的则会报错 const offset = JSON.parse(node.getAttribute('offset') || '[]'); // 如果是数组,那么不论写了多少个值都只返回前两个 if (type.isArr(offset) && offset.length > 0) { return { x: offset[0], y: offset[1] }; } } private _getStatus(node: Element): string { return node.getAttribute('status') || ''; } private _getColor(node: Element): string { return node.getAttribute('color') || ''; } private _getText(node: Element): string { return node.getAttribute('text') || ''; } private _showZero(node: Element): boolean { return node.getAttribute('show-zero') === 'true'; } private _showDot(node: Element): boolean { return node.getAttribute('dot') === 'true'; } } export default Badge;