/** * 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;