system-apps/apps/ui/deploy/message.js
2024-11-01 23:53:45 +08:00

277 lines
7.7 KiB
JavaScript

export class MessageContainer {
container;
id = 'for-message';
root = document.body;
constructor(opts) {
const { id } = opts || {};
if (id) {
this.id = id;
}
this.initContainer();
}
initContainer() {
const id = this.id;
const root = this.root;
let forModal = document.querySelector('#' + id);
if (!forModal) {
forModal = document.createElement('div');
forModal.id = id;
forModal.style = ``;
// 点击穿透
root.appendChild(forModal);
}
this.initStyle();
this.container = forModal;
}
initStyle(force) {
const id = this.id;
const styleId = id + '-style';
const _style = document.querySelector('#' + styleId);
if (force && _style) {
_style.remove();
}
if (!force && _style) {
return;
}
const style = document.createElement('style');
style.id = styleId;
style.innerHTML = `
#${id} {
position: fixed; top: 0; left: 0; z-index: 1000; width: 100vw;height: 100vh;pointer-events: none; display: flex; flex-direction: column; gap: 10px;
}
.message-wrapper {
display: flex;
transition: transform 2s ease-in-out, opacity 1.2s ease-in-out; /* 缩小并淡出 */
}
.message-wrapper:first-child {
margin-top: 20px;
}
.message {
display: flex;
gap: 10px;
padding: 6px 10px;
margin: 0 auto;
border-radius: 4px;
background-color: white;
box-shadow: 0 6px 16px 0 rgba(0, 0, 0, 0.08),
0 3px 6px -4px rgba(0, 0, 0, 0.12),
0 9px 28px 8px rgba(0, 0, 0, 0.05);
justify-content: center;
align-item: center;
animation: message-slide-down 0.3s ease-out forwards; /* 应用动画 */
}
/* 添加消失类时 */
.message-wrapper.message-hide {
transform: scale(0);
opacity: 0;
pointer-events: none; /* 防止交互 */
}
.message-success {
}
@keyframes message-slide-down {
0% {
transform: translateY(-100px); /* 从上方开始 */
opacity: 0; /* 从不可见状态开始 */
}
50% {
opacity: 0.5; /* 渐渐变为半透明 */
}
100% {
transform: translateY(0); /* 移动到初始位置 */
opacity: 1; /* 最终完全可见 */
}
}
.message-icon {
position: relative;
width: 24px;
height: 24px;
box-sizing: border-box;
}
.message-icon::before {
content: "";
position: absolute;
left: 7px;
top: 3px;
width: 5px;
height: 10px;
}
.icon-success {
border: 2px solid green; /* 外圆圈 */
border-radius: 50%; /* 使其为圆形 */
}
.icon-success::before {
border-right: 2px solid green; /* 打勾的右边部分 */
border-bottom: 2px solid green; /* 打勾的下边部分 */
transform: rotate(45deg);
}
.icon-info {
border: 2px solid blue; /* 外圆圈 */
border-radius: 50%; /* 使其为圆形 */
}
.icon-info::before {
content: "i";
position: absolute;
top: 0px;
color: blue;
font-weight: bold;
font-size: 16px;
left: 8px;
}
.icon-error::before, .icon-error::after {
content: "";
position: absolute;
top: 4px;
left: 50%;
width: 2px;
height: 12px;
background-color: red;
transform-origin: center;
}
.icon-error {
border: 2px solid red; /* 外圆圈 */
border-radius: 50%; /* 使其为圆形 */
}
.icon-error::before {
transform: translateX(-50%) rotate(45deg); /* 旋转形成叉号的一部分 */
}
.icon-error::after {
transform: translateX(-50%) rotate(-45deg); /* 旋转形成叉号的另一部分 */
}
.icon-warning {
position: relative;
width: 0;
height: 0;
border-left: 12px solid transparent;
border-right: 12px solid transparent;
border-bottom: 24px solid orange; /* 三角形 */
display: inline-block;
transform: scale(0.8); /* 缩小三角形 */
}
.icon-warning::before {
content: "!";
position: absolute;
top: 5px;
left: 50%;
transform: translateX(-50%);
color: white;
font-weight: bold;
font-size: 16px;
}
.icon-loading {
width: 24px;
height: 24px;
border: 3px solid #f3f3f3; /* 边框颜色,用于加载圈的背景 */
border-top: 3px solid #3498db; /* 顶部边框的颜色,用于显示加载进度 */
border-radius: 50%; /* 圆形 */
animation: spin 1s linear infinite; /* 旋转动画 */
}
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
`;
document.head.appendChild(style);
}
setRoot(root) {
if (root instanceof HTMLElement) {
this.root = root;
root.appendChild(this.container);
}
}
}
const controller = new MessageContainer();
export const createMessage = (content, opts) => {
let { icon, key, style, className, type } = opts || {};
const div = document.createElement('div');
div.className = 'message-wrapper' + (className ? ' ' + className : '');
if (style) div.style = style;
if (key) div.setAttribute('data-key', key);
const contentDiv = document.createElement('div');
contentDiv.className = 'message';
if (icon) {
const i = document.createElement('i');
i.className = icon;
i.classList.add('message-icon');
contentDiv.appendChild(i);
} else if (type) {
const i = document.createElement('div');
i.className = 'icon-' + type;
i.classList.add('message-icon');
contentDiv.appendChild(i);
}
if (content instanceof HTMLElement) {
contentDiv.appendChild(content);
} else {
const text = document.createElement('span');
text.innerText = content;
contentDiv.appendChild(text);
}
div.appendChild(contentDiv);
return div;
};
const methods = ['success', 'info', 'warning', 'error', 'loading'];
export class Message {
controller = controller;
constructor() {
this.controller = controller;
}
open = (message, timeout = 3000, onClose, opts) => {
const controller = this.controller;
const div = createMessage(message, opts);
const remove = () => {
div.classList.add('message-hide');
setTimeout(() => {
if (div?.isConnected) {
div.remove();
} else {
console.log('not connected');
controller.container.removeChild(div);
}
}, 1000);
onClose && onClose();
};
controller.container.appendChild(div);
controller.initStyle(true);
if (timeout === 0) {
return () => {
remove();
};
}
const time = setTimeout(() => {
remove();
}, timeout);
return () => {
clearTimeout(time);
remove();
};
};
success = (message, timeout = 1000, onClose = () => {}) => {
return this.open(message, timeout, onClose, { type: 'success' });
};
info = (message, timeout = 1500, onClose = () => {}) => {
return this.open(message, timeout, onClose, { type: 'info' });
};
warning = (message, timeout = 3000, onClose = () => {}) => {
return this.open(message, timeout, onClose, { type: 'warning' });
};
error = (message, timeout = 3000, onClose = () => {}) => {
return this.open(message, timeout, onClose, { type: 'error' });
};
loading = (message, timeout = 0, onClose = () => {}) => {
return this.open(message, timeout, onClose, { type: 'loading' });
};
}
export const message = new Message();