236 lines
6.5 KiB
JavaScript
236 lines
6.5 KiB
JavaScript
// 终极消息系统 (保留所有优秀特性)
|
||
(() => {
|
||
// 完美图标系统
|
||
const icons = {
|
||
success: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" class="msg-svg"><path fill="currentColor" d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 15l-4-4 1.41-1.41L11 14.17l6.59-6.59L19 9l-8 8z"/></svg>',
|
||
error: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" class="msg-svg"><path fill="currentColor" d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm5 13.59L15.59 17 12 13.41 8.41 17 7 15.59 10.59 12 7 8.41 8.41 7 12 10.59 15.59 7 17 8.41 13.41 12 17 15.59z"/></svg>',
|
||
warning: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" class="msg-svg"><path fill="currentColor" d="M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z"/></svg>',
|
||
info: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" class="msg-svg"><path fill="currentColor" d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z"/></svg>'
|
||
};
|
||
|
||
// 专业配置系统
|
||
const config = {
|
||
duration: 3000,
|
||
spacing: 10,
|
||
maxMessages: 10,
|
||
closable: false,
|
||
enterAnimation: 'msg-slideIn',
|
||
exitAnimation: 'msg-fadeOutUp'
|
||
};
|
||
|
||
// 完美样式系统
|
||
const style = document.createElement('style');
|
||
style.textContent = `
|
||
@keyframes msg-slideIn {
|
||
0% { opacity: 0; transform: translate(-50%, -20px);
|
||
filter: blur(5px); }
|
||
100% { opacity: 1; transform: translate(-50%, 0);
|
||
filter: blur(0px); }
|
||
}
|
||
|
||
@keyframes msg-fadeOutUp {
|
||
0% { opacity: 1; transform: translate(-50%, 0);
|
||
filter: blur(0px); }
|
||
100% { opacity: 0; transform: translate(-50%, -100px);
|
||
filter: blur(5px); }
|
||
}
|
||
|
||
.msg {
|
||
position: fixed;
|
||
left: 50%;
|
||
transform: translateX(-50%);
|
||
min-width: 300px;
|
||
max-width: 90vw;
|
||
padding: 14px 20px;
|
||
border-radius: 15px;
|
||
background: #fff;
|
||
|
||
display: flex;
|
||
align-items: center;
|
||
z-index: 9999;
|
||
opacity: 0;
|
||
transition: top 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
|
||
font-family: system-ui, sans-serif;
|
||
}
|
||
|
||
.msg-enter {
|
||
animation: ${config.enterAnimation} 0.5s forwards;
|
||
}
|
||
|
||
.msg-exit {
|
||
animation: ${config.exitAnimation} 0.5s forwards;
|
||
}
|
||
|
||
.msg-icon {
|
||
width: 24px;
|
||
height: 24px;
|
||
margin-right: 12px;
|
||
flex-shrink: 0;
|
||
animation: msg-content-in 0.4s ease-in-out 0.5s forwards;
|
||
}
|
||
|
||
.msg-content {
|
||
flex: 1;
|
||
font-size: 14px;
|
||
line-height: 1.5;
|
||
padding-right: 8px;
|
||
transition: all 0.5s;
|
||
animation: msg-content-in 0.4s ease-in-out 0.55s forwards;
|
||
}
|
||
@keyframes msg-content-in {
|
||
0% { opacity: 1;
|
||
filter: blur(0px); }
|
||
50% { opacity: 1;
|
||
filter: blur(2px); }
|
||
} 100% { opacity: 1;
|
||
filter: blur(0px); }
|
||
}
|
||
|
||
.msg-close {
|
||
cursor: pointer;
|
||
width: 24px;
|
||
height: 24px;
|
||
margin-left: 8px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
border-radius: 6px;
|
||
transition: all 0.5s;
|
||
color: rgba(0,0,0,0.5);
|
||
flex-shrink: 0;
|
||
animation: msg-content-in 0.4s ease-in-out 0.6s forwards;
|
||
}
|
||
|
||
.msg-close:hover {
|
||
background: rgba(0,0,0,0.08);
|
||
color: rgba(0,0,0,0.8);
|
||
}
|
||
|
||
/* 专业配色方案 */
|
||
.msg-success { color: #10B981; box-shadow: 0px 0px 4px rgba(16, 185, 129, 0.2);}
|
||
.msg-error { color: #EF4444; box-shadow: 0px 0px 4px rgba(239, 68, 68, 0.2);}
|
||
.msg-warning { color: #F59E0B; box-shadow: 0px 0px 4px rgba(245, 158, 11, 0.2);}
|
||
.msg-info { color: #3B82F6; box-shadow: 0px 0px 4px rgba(59, 130, 246, 0.2);}
|
||
|
||
`;
|
||
document.head.appendChild(style);
|
||
|
||
// 终极消息管理器
|
||
class MsgManager {
|
||
static instances = [];
|
||
|
||
static add(msg) {
|
||
if (this.instances.length >= config.maxMessages) {
|
||
this.instances[0].close();
|
||
}
|
||
this.instances.push(msg);
|
||
this.updateLayout();
|
||
}
|
||
|
||
static remove(msg) {
|
||
const index = this.instances.indexOf(msg);
|
||
if (index > -1) {
|
||
this.instances.splice(index, 1);
|
||
this.updateLayout(true);
|
||
}
|
||
}
|
||
|
||
static updateLayout(animate = false) {
|
||
let top = 20;
|
||
this.instances.forEach(instance => {
|
||
instance.element.style.transition = animate ? 'top 0.5s cubic-bezier(0.34, 1.56, 0.64, 1)' : 'none';
|
||
instance.element.style.top = `${top}px`;
|
||
top += instance.element.offsetHeight + config.spacing;
|
||
});
|
||
}
|
||
}
|
||
|
||
// 完美消息实例
|
||
class Msg {
|
||
constructor(type, content, options) {
|
||
this.type = type;
|
||
this.content = content;
|
||
this.options = { ...config, ...options };
|
||
this.element = this.createElement();
|
||
this.setupEvents();
|
||
this.show();
|
||
}
|
||
|
||
createElement() {
|
||
const el = document.createElement('div');
|
||
el.className = `msg msg-${this.type}`;
|
||
|
||
const closeBtn = this.options.closable
|
||
? '<div class="msg-close" role="button">×</div>'
|
||
: '';
|
||
|
||
el.innerHTML = `
|
||
<div class="msg-icon">${icons[this.type]}</div>
|
||
<div class="msg-content">${this.content}</div>
|
||
${closeBtn}
|
||
`;
|
||
|
||
return el;
|
||
}
|
||
|
||
setupEvents() {
|
||
if (this.options.closable) {
|
||
this.element.querySelector('.msg-close').addEventListener('click', () => this.close());
|
||
}
|
||
}
|
||
|
||
show() {
|
||
document.body.appendChild(this.element);
|
||
requestAnimationFrame(() => {
|
||
this.element.classList.add('msg-enter');
|
||
MsgManager.add(this);
|
||
});
|
||
this.autoCloseTimer = setTimeout(() => this.close(), this.options.duration);
|
||
}
|
||
|
||
close() {
|
||
clearTimeout(this.autoCloseTimer);
|
||
this.element.classList.remove('msg-enter');
|
||
this.element.classList.add('msg-exit');
|
||
|
||
setTimeout(() => {
|
||
this.element.remove();
|
||
MsgManager.remove(this);
|
||
}, 500);
|
||
}
|
||
}
|
||
|
||
// 终极API暴露
|
||
const Message = {
|
||
config(newConfig) {
|
||
Object.assign(config, newConfig);
|
||
},
|
||
|
||
success(content, options) {
|
||
return new Msg('success', content, options);
|
||
},
|
||
|
||
error(content, options) {
|
||
return new Msg('error', content, options);
|
||
},
|
||
|
||
warning(content, options) {
|
||
return new Msg('warning', content, options);
|
||
},
|
||
|
||
info(content, options) {
|
||
return new Msg('info', content, options);
|
||
},
|
||
|
||
closeAll() {
|
||
MsgManager.instances.slice().forEach(msg => msg.close());
|
||
}
|
||
};
|
||
|
||
window.Message = Message;
|
||
})();
|
||
|
||
// 完美调用示例
|
||
//Message.success('');
|
||
//Message.error('验证失败', { closable: true, duration: 5000 });
|