模态对话框

接口

interface IModal {
    root: HTMLElement;
    container: HTMLElement;
    content: HTMLElement;

    mount(root?: HTMLElement): IModal;
    remove(): IModal;
    appendContent(content: HTMLElement): IModal;
    appendHeader(title: string, close?: boolean, onClose?: (modal: IModal) => void): IModal;
}

code

/**
 * 计算el元素及其子元素的z-index最大值
 */
function calcZIndex(el: HTMLElement = document.body): number {
    var max = el['computedStyleMap'] ?
        el['computedStyleMap']().get('z-index').unit === 'number' ? Number.parseInt(el['computedStyleMap']().get('z-index').value) : 0
        :
        el.style.zIndex === '' ? 0 : Number.parseInt(el.style.zIndex);
    Array.from(el.children).forEach(it => {
        var childZIndex = calcZIndex(it as HTMLElement);
        if (childZIndex > max) {
            max = childZIndex;
        }
    })
    return max;
}

function setStyles(el: HTMLElement, styles) {
// function setStyles(el: HTMLElement, styles: React.CSSProperties) {
    for (let key in styles) {
        el.style[key] = styles[key];
    }
}

class Modal implements IModal {
    root: HTMLElement;
    container: HTMLElement;
    content: HTMLElement;

    constructor() {
        var container = document.createElement('div');
        this.container = container;
        setStyles(container, {
            position: 'absolute',
            top: 0,
            left: 0,
            width: '100%',
            height: '100%',
            background: 'transparent',
        });
        this.createContent();
    }
    private createContent() {
        var content = document.createElement('div');
        this.content = content;
        setStyles(content, {
            position: 'absolute',
            minWidth: '180px',
            minHeight: '100px',
            top: '40%',
            left: '50%',
            transform: 'translate(-50%, -50%) scale(0)',
            transition: '0.2s transform',
            background: 'rgba(255, 255, 255, 0)',
        });
        this.container.appendChild(content);
    }
    appendContent(content: HTMLElement): IModal {
        this.content.appendChild(content);
        return this;
    }
    mount(root: HTMLElement = document.body): IModal {
        root.appendChild(this.container);
        this.root = root;
        setStyles(this.container, {
            zIndex: calcZIndex(root) + 1,
        });
        this.content.style.transform = 'translate(-50%, -50%) scale(1)';
        return this;
    }
    remove(): IModal {
        this.root.removeChild(this.container);
        this.content.style.transform = 'translate(-50%, -50%) scale(0)';
        return this;
    }
    appendHeader(title: string = '', close: boolean = true, onClose: (modal: IModal) => void = () => { this.remove() }): IModal {
        var header = document.createElement('div');
        setStyles(header, {
            margin: '2px 2px',
            position: 'relative',
            width: '100%',
            paddingBottom: '20px',
        });
        header.innerHTML = `
            <h2 style="margin: 4px 0; display: inline-block">${title}</h2>
            <button cmd="remove" style="${close ? '' : 'display: none;'}">X</button>
        `;
        var button: HTMLButtonElement = header.querySelector(`*[cmd="remove"]`);
        setStyles(button, {
            border: 'none',
            padding: '8px',
            cursor: 'pointer',
            userSelect: 'none',
            position: 'absolute',
            right: '6px',
            top: '2px',
            background: '#dc3545',
            color: 'white',
            borderRadius: '5px',
            width: '50px',
        });
        button.addEventListener('click', () => {
            onClose(this);
        });
        this.content.insertBefore(
            header,
            this.content.firstElementChild
        );
        return this;
    }
}

export default Modal;

END

posted @ 2021-10-12 17:26  develon  阅读(81)  评论(0编辑  收藏  举报