接口
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