/**
* Toast 消息提醒组件 - iOS风格
* 使用方法:
* Toast.show('消息内容')
* Toast.success('成功消息')
* Toast.error('错误消息')
* Toast.warning('警告消息')
* Toast.info('提示消息')
*/
const Toast = (function() {
// 消息类型配置
const TYPES = {
success: {
icon: '✓',
color: '#34C759',
iconBg: 'rgba(52, 199, 89, 0.15)'
},
error: {
icon: '✕',
color: '#FF3B30',
iconBg: 'rgba(255, 59, 48, 0.15)'
},
warning: {
icon: '!',
color: '#FF9500',
iconBg: 'rgba(255, 149, 0, 0.15)'
},
info: {
icon: 'i',
color: '#007AFF',
iconBg: 'rgba(0, 122, 255, 0.15)'
}
};
// 默认配置
const DEFAULT_OPTIONS = {
duration: 2500, // 显示时长(毫秒)
position: 'top-center', // 位置:top-center, top-right, bottom-center, center
showIcon: true, // 是否显示图标
animation: true // 是否使用动画
};
// 当前显示的toast队列
let toastQueue = [];
let container = null;
/**
* 初始化容器
*/
function initContainer() {
if (!container) {
container = document.createElement('div');
container.className = 'toast-container';
document.body.appendChild(container);
}
return container;
}
/**
* 创建Toast元素
*/
function createToast(message, type = 'info', options = {}) {
const opts = { ...DEFAULT_OPTIONS, ...options };
const config = TYPES[type] || TYPES.info;
const toast = document.createElement('div');
toast.className = `toast toast-${type} toast-${opts.position}`;
if (opts.animation) {
toast.classList.add('toast-enter');
}
// 构建toast内容
let html = '
';
if (opts.showIcon) {
html += `
${config.icon}
`;
}
html += `
${message}
`;
toast.innerHTML = html;
return { element: toast, duration: opts.duration };
}
/**
* 显示Toast
*/
function show(message, type = 'info', options = {}) {
const toastContainer = initContainer();
const { element, duration } = createToast(message, type, options);
// 添加到DOM
toastContainer.appendChild(element);
toastQueue.push(element);
// 触发入场动画
setTimeout(() => {
element.classList.remove('toast-enter');
element.classList.add('toast-visible');
}, 10);
// 自动移除
setTimeout(() => {
hide(element);
}, duration);
return element;
}
/**
* 隐藏Toast
*/
function hide(toastElement) {
if (!toastElement || !toastElement.parentNode) return;
toastElement.classList.remove('toast-visible');
toastElement.classList.add('toast-exit');
setTimeout(() => {
if (toastElement.parentNode) {
toastElement.parentNode.removeChild(toastElement);
}
// 从队列中移除
const index = toastQueue.indexOf(toastElement);
if (index > -1) {
toastQueue.splice(index, 1);
}
// 如果队列为空,移除容器
if (toastQueue.length === 0 && container) {
container.remove();
container = null;
}
}, 300);
}
/**
* 清除所有Toast
*/
function clear() {
toastQueue.forEach(toast => hide(toast));
toastQueue = [];
}
// 快捷方法
function success(message, options) {
return show(message, 'success', options);
}
function error(message, options) {
return show(message, 'error', options);
}
function warning(message, options) {
return show(message, 'warning', options);
}
function info(message, options) {
return show(message, 'info', options);
}
/**
* 提示对话框(iOS风格,只有一个确定按钮)
*/
function alert(options = {}) {
// 支持直接传字符串或对象
if (typeof options === 'string') {
options = { message: options };
}
return new Promise((resolve) => {
const opts = {
title: options.title || '',
message: options.message || '',
confirmText: options.confirmText || i18n?.t?.('confirm') || '确定',
confirmColor: options.confirmColor || '#007AFF',
...options
};
// 创建遮罩层
const overlay = document.createElement('div');
overlay.className = 'toast-overlay';
// 创建对话框
const dialog = document.createElement('div');
dialog.className = 'toast-dialog';
let html = '';
if (opts.title) {
html += `
${opts.title}
`;
}
if (opts.message) {
html += `
${opts.message}
`;
}
// 只有一个确定按钮
html += `
`;
dialog.innerHTML = html;
// 添加到DOM
overlay.appendChild(dialog);
document.body.appendChild(overlay);
// 触发动画
setTimeout(() => {
overlay.classList.add('toast-overlay-visible');
dialog.classList.add('toast-dialog-visible');
}, 10);
// 按钮事件
const confirmBtn = dialog.querySelector('.toast-dialog-confirm');
function close() {
overlay.classList.remove('toast-overlay-visible');
dialog.classList.remove('toast-dialog-visible');
setTimeout(() => {
overlay.remove();
}, 300);
}
confirmBtn.addEventListener('click', () => {
close();
resolve(true);
});
// 点击遮罩关闭
if (opts.closeOnClickOverlay !== false) {
overlay.addEventListener('click', (e) => {
if (e.target === overlay) {
close();
resolve(true);
}
});
}
});
}
/**
* 确认对话框(iOS风格)
*/
function confirm(options = {}) {
return new Promise((resolve, reject) => {
const opts = {
title: options.title || '',
message: options.message || '',
confirmText: options.confirmText || i18n.t('confirm') || '确定',
cancelText: options.cancelText || i18n.t('cancel') || '取消',
confirmColor: options.confirmColor || '#007AFF',
cancelColor: options.cancelColor || '#8E8E93',
...options
};
// 创建遮罩层
const overlay = document.createElement('div');
overlay.className = 'toast-overlay';
// 创建对话框
const dialog = document.createElement('div');
dialog.className = 'toast-dialog';
let html = '';
if (opts.title) {
html += `
${opts.title}
`;
}
if (opts.message) {
html += `
${opts.message}
`;
}
html += `
`;
dialog.innerHTML = html;
// 添加到DOM
overlay.appendChild(dialog);
document.body.appendChild(overlay);
// 触发动画
setTimeout(() => {
overlay.classList.add('toast-overlay-visible');
dialog.classList.add('toast-dialog-visible');
}, 10);
// 按钮事件
const confirmBtn = dialog.querySelector('.toast-dialog-confirm');
const cancelBtn = dialog.querySelector('.toast-dialog-cancel');
function close() {
overlay.classList.remove('toast-overlay-visible');
dialog.classList.remove('toast-dialog-visible');
setTimeout(() => {
overlay.remove();
}, 300);
}
confirmBtn.addEventListener('click', () => {
close();
resolve(true);
});
cancelBtn.addEventListener('click', () => {
close();
resolve(false);
});
// 点击遮罩关闭
if (opts.closeOnClickOverlay !== false) {
overlay.addEventListener('click', (e) => {
if (e.target === overlay) {
close();
resolve(false);
}
});
}
});
}
/**
* 输入对话框(iOS风格)
*/
function prompt(options = {}) {
return new Promise((resolve, reject) => {
const opts = {
title: options.title || '',
message: options.message || '',
placeholder: options.placeholder || '',
defaultValue: options.defaultValue || '',
inputType: options.inputType || 'text',
confirmText: options.confirmText || i18n.t('confirm') || '确定',
cancelText: options.cancelText || i18n.t('cancel') || '取消',
confirmColor: options.confirmColor || '#007AFF',
cancelColor: options.cancelColor || '#8E8E93',
maxLength: options.maxLength || null,
...options
};
// 创建遮罩层
const overlay = document.createElement('div');
overlay.className = 'toast-overlay';
// 创建对话框
const dialog = document.createElement('div');
dialog.className = 'toast-dialog toast-prompt-dialog';
let html = '';
if (opts.title) {
html += `
${opts.title}
`;
}
if (opts.message) {
html += `
${opts.message}
`;
}
// 输入框
const maxLengthAttr = opts.maxLength ? `maxlength="${opts.maxLength}"` : '';
html += `
`;
html += `
`;
dialog.innerHTML = html;
// 添加到DOM
overlay.appendChild(dialog);
document.body.appendChild(overlay);
// 获取输入框
const input = dialog.querySelector('.toast-input');
const confirmBtn = dialog.querySelector('.toast-dialog-confirm');
const cancelBtn = dialog.querySelector('.toast-dialog-cancel');
// 触发动画
setTimeout(() => {
overlay.classList.add('toast-overlay-visible');
dialog.classList.add('toast-dialog-visible');
// 自动聚焦并选中文本
input.focus();
if (opts.defaultValue) {
input.select();
}
}, 10);
function close() {
overlay.classList.remove('toast-overlay-visible');
dialog.classList.remove('toast-dialog-visible');
setTimeout(() => {
overlay.remove();
}, 300);
}
function handleConfirm() {
const value = input.value;
close();
resolve(value);
}
function handleCancel() {
close();
resolve(null);
}
// 按钮事件
confirmBtn.addEventListener('click', handleConfirm);
cancelBtn.addEventListener('click', handleCancel);
// 回车确认
input.addEventListener('keypress', (e) => {
if (e.key === 'Enter') {
handleConfirm();
}
});
// ESC取消
input.addEventListener('keydown', (e) => {
if (e.key === 'Escape') {
handleCancel();
}
});
// 点击遮罩关闭
if (opts.closeOnClickOverlay !== false) {
overlay.addEventListener('click', (e) => {
if (e.target === overlay) {
handleCancel();
}
});
}
});
}
// 导出API
return {
show,
success,
error,
warning,
info,
alert,
confirm,
prompt,
clear,
hide
};
})();
// 全局暴露
window.Toast = Toast;