rabbit-design
Version:
A lightweight UI plugin library written in TypeScript and based on JavaScript
154 lines (120 loc) • 4.77 kB
text/typescript
import { $el, bind, setCss, setHtml } from '../../dom-utils';
import { type, validComps } from '../../utils';
import PREFIX from '../prefix';
interface Config {
onChange(elem: string, cb: ([status, $this]: [boolean, Element]) => void): void;
}
class Switch implements Config {
readonly VERSION: string;
readonly COMPONENTS: NodeListOf<Element>;
constructor() {
this.VERSION = '1.0';
this.COMPONENTS = $el('r-switch', { all: true });
this._create(this.COMPONENTS);
}
public onChange(elem: string, cb: ([status, $this]: [boolean, Element]) => void): void {
const target = $el(elem);
validComps(target, 'switch');
// 将当前选中的组件作为参数返回出去
const $this = target;
bind(target, 'click', () => {
const status = this._getStatus(target);
type.isFn(cb, [status, $this]);
});
}
private _create(COMPONENTS: NodeListOf<Element>): void {
COMPONENTS.forEach((node) => {
this._init(node);
this._handleChange(node, this._getStatus(node));
});
}
private _init(node: Element): void {
// 初始化按键切换索引
node.setAttribute('tabindex', '0');
// 初始化未选中状态的开关
if (node.getAttribute('checked') !== 'true') {
node.setAttribute('checked', 'false');
}
this._setStatusText(node, this._getStatus(node));
this._setStatusColor(node, this._getStatus(node));
}
// 设置自定义的状态文本
private _setStatusText(node: Element, status: boolean): void {
const { openText, closeText } = this._getStatusText(node);
if (!openText || !closeText) return;
// 创建文本容器
const TextBox = document.createElement('span');
TextBox.className = `${PREFIX.switch}-inner`;
node.appendChild(TextBox);
status ? setHtml(TextBox, openText) : setHtml(TextBox, closeText);
}
// 设置自定义的状态颜色
private _setStatusColor(node: any, status: boolean): void {
const { trueColor, falseColor } = this._getColor(node);
if (!trueColor || !falseColor) return;
if (status) {
setCss(node, 'borderColor', trueColor);
setCss(node, 'backgroundColor', trueColor);
} else {
setCss(node, 'borderColor', falseColor);
setCss(node, 'backgroundColor', falseColor);
}
}
private _handleChange(node: Element, status: boolean): void {
const ev_change = () => {
if (this._isDisabled(node)) return false;
if (this._isLoading(node)) return false;
status ? (status = false) : (status = true);
node.setAttribute('checked', `${status}`);
const { openText, closeText } = this._getStatusText(node);
this._changeStatusText(node, status, openText, closeText);
this._setStatusColor(node, status);
};
node.addEventListener('click', ev_change);
}
private _changeStatusText(node: Element, status: boolean, openText: any, closeText: any): void {
// 获取当前开关下的文本容器
const TextBox = node.querySelector(`.${PREFIX.switch}-inner`);
if (TextBox) {
status ? setHtml(TextBox, openText) : setHtml(TextBox, closeText);
}
}
private _getStatus(node: Element): boolean {
// 转换为真实布尔类型
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
return JSON.parse(node.getAttribute('checked')!);
}
private _isDisabled(node: Element): boolean {
return (
node.getAttribute('disabled') === 'disabled' ||
node.getAttribute('disabled') === 'true' ||
node.getAttribute('disabled') === ''
);
}
private _isLoading(node: Element): boolean {
return node.getAttribute('rb-loading') === 'true';
}
private _getStatusText(
node: Element
): {
openText: string | null;
closeText: string | null;
} {
return {
openText: node.getAttribute('rb-open'),
closeText: node.getAttribute('rb-close')
};
}
private _getColor(
node: Element
): {
trueColor: string | null;
falseColor: string | null;
} {
return {
trueColor: node.getAttribute('rb-true-color'),
falseColor: node.getAttribute('rb-false-color')
};
}
}
export default Switch;