/**
* Message 消息通知组件
* 自动注入必要样式,无需额外引入 CSS
*
* 使用方式:
* const message = new Message();
* message.create({ type: 'success', content: '操作成功' });
*
* 快捷方法:
* message.success('内容')
* message.warning('内容')
* message.danger('内容')
* message.info('内容')
* message.default('内容')
* message.success('操作成功', {duration: 5000, showClose: false,showProgress: false,pale: false,html: false});
*/
(function (global) {
'use strict';
const STYLE_ID = 'message-component-style';
const CSS = `
/* ==================== Message Component Styles ==================== */
.message-container {
position: fixed;
top: 20px;
left: 50%;
transform: translateX(-50%);
z-index: 999999;
display: flex;
flex-direction: column;
align-items: center;
gap: 12px;
pointer-events: none;
}
.message-item {
pointer-events: auto;
min-width: 320px;
max-width: 600px;
padding: 14px 18px;
border-radius: 3px;
background: #fff;
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);
display: flex;
align-items: flex-start;
gap: 12px;
position: relative;
transition: all 0.35s cubic-bezier(0.4, 0, 0.2, 1);
opacity: 0;
transform: translateY(-30px);
}
.message-item.message-enter {
opacity: 1;
transform: translateY(0);
}
.message-item.message-leave {
opacity: 0;
transform: translateY(-20px);
margin-top: -58px;
}
.message-icon {
width: 20px;
height: 20px;
flex-shrink: 0;
margin-top: 2px;
}
.message-content {
flex: 1;
font-size: 14px;
line-height: 1.6;
color: #333;
word-break: break-word;
}
.message-close {
width: 18px;
height: 18px;
flex-shrink: 0;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
border-radius: 3px;
transition: all 0.2s;
margin-top: 2px;
}
.message-close:hover {
background: rgba(0,0,0,0.06);
}
.message-close svg {
width: 14px;
height: 14px;
}
.message-item.message-default .message-icon { color: #6c757d; }
.message-item.message-success .message-icon { color: #28a745; }
.message-item.message-warning .message-icon { color: #e6a700; }
.message-item.message-danger .message-icon { color: #dc3545; }
.message-item.message-info .message-icon { color: #17a2b8; }
.message-item.message-pale.message-default { background: #f8f9fa; border: 1px solid #e9ecef; }
.message-item.message-pale.message-success { background: #f0f9f4; border: 1px solid #d4edda; }
.message-item.message-pale.message-warning { background: #fffbf0; border: 1px solid #ffeeba; }
.message-item.message-pale.message-danger { background: #fdf2f2; border: 1px solid #f5c6cb; }
.message-item.message-pale.message-info { background: #f0f9fb; border: 1px solid #bee5eb; }
.message-progress {
position: absolute;
bottom: 0;
left: 0;
height: 3px;
border-radius: 0 0 0 3px;
transition: width linear;
}
.message-default .message-progress { background: #6c757d; }
.message-success .message-progress { background: #28a745; }
.message-warning .message-progress { background: #ffc107; }
.message-danger .message-progress { background: #dc3545; }
.message-info .message-progress { background: #17a2b8; }
`;
function injectStyle() {
if (document.getElementById(STYLE_ID)) return;
const style = document.createElement('style');
style.id = STYLE_ID;
style.textContent = CSS;
document.head.appendChild(style);
}
const ICONS = {
default: ``,
success: ``,
warning: ``,
danger: ``,
info: ``
};
class Message {
constructor(options = {}) {
injectStyle();
this.container = null;
this.messages = [];
this.defaultOptions = {
type: 'default',
pale: false,
duration: 3000,
showClose: true,
showProgress: true,
content: '',
html: false
};
}
_ensureContainer() {
if (!this.container || !document.body.contains(this.container)) {
this.container = document.createElement('div');
this.container.className = 'message-container';
this.container.id = 'messageContainer';
document.body.appendChild(this.container);
}
return this.container;
}
create(options) {
const opts = { ...this.defaultOptions, ...options };
const id = 'msg_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9);
const container = this._ensureContainer();
const el = document.createElement('div');
el.className = `message-item message-${opts.type}`;
if (opts.pale) el.classList.add('message-pale');
el.id = id;
const iconEl = document.createElement('div');
iconEl.className = 'message-icon';
iconEl.innerHTML = ICONS[opts.type] || ICONS.default;
const contentEl = document.createElement('div');
contentEl.className = 'message-content';
if (opts.html) {
contentEl.innerHTML = opts.content;
} else {
contentEl.textContent = opts.content;
}
el.appendChild(iconEl);
el.appendChild(contentEl);
if (opts.showClose) {
const closeEl = document.createElement('div');
closeEl.className = 'message-close';
closeEl.innerHTML = ``;
closeEl.addEventListener('click', () => this.close(id));
el.appendChild(closeEl);
}
let progressEl = null;
if (opts.duration > 0 && opts.showProgress) {
progressEl = document.createElement('div');
progressEl.className = 'message-progress';
progressEl.style.width = '100%';
el.appendChild(progressEl);
}
container.appendChild(el);
const msgInfo = {
id,
el,
duration: opts.duration,
timer: null,
startTime: null
};
this.messages.push(msgInfo);
requestAnimationFrame(() => {
requestAnimationFrame(() => {
el.classList.add('message-enter');
});
});
if (opts.duration > 0) {
msgInfo.startTime = Date.now();
if (progressEl) {
requestAnimationFrame(() => {
progressEl.style.transition = `width ${opts.duration}ms linear`;
requestAnimationFrame(() => {
progressEl.style.width = '0%';
});
});
}
msgInfo.timer = setTimeout(() => {
this.close(id);
}, opts.duration);
}
return id;
}
close(id) {
const index = this.messages.findIndex(m => m.id === id);
if (index === -1) return;
const msg = this.messages[index];
if (msg.timer) {
clearTimeout(msg.timer);
msg.timer = null;
}
msg.el.classList.remove('message-enter');
msg.el.classList.add('message-leave');
setTimeout(() => {
if (msg.el.parentNode) {
msg.el.parentNode.removeChild(msg.el);
}
const idx = this.messages.findIndex(m => m.id === id);
if (idx !== -1) this.messages.splice(idx, 1);
}, 350);
}
closeAll() {
[...this.messages].forEach(msg => this.close(msg.id));
}
success(content, options = {}) {
return this.create({ ...options, type: 'success', content });
}
warning(content, options = {}) {
return this.create({ ...options, type: 'warning', content });
}
danger(content, options = {}) {
return this.create({ ...options, type: 'danger', content });
}
error(content, options = {}) {
return this.create({ ...options, type: 'danger', content });
}
info(content, options = {}) {
return this.create({ ...options, type: 'info', content });
}
default(content, options = {}) {
return this.create({ ...options, type: 'default', content });
}
}
global.Message = Message;
})(typeof window !== 'undefined' ? window : this);
const message = new Message();