您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Greasy Fork is available in English.
可被其他油猴脚本引用的toast提示组件(修复版)
当前为
此脚本不应直接安装。它是供其他脚本使用的外部库,要使用该库请加入元指令 // @require https://update.greasyfork.icu/scripts/548898/1657481/Toast%E7%BB%84%E4%BB%B6%E6%A8%A1%E5%9D%97.js
// ==UserScript== // @name Toast组件模块 // @namespace http://tampermonkey.net/ // @version 1.0.1 // @description 可被其他油猴脚本引用的toast提示组件(修复版) // @author You // @match * // @grant none // @noframes // ==/UserScript== (function(window) { 'use strict'; // 防止重复加载 if (window.MonkeyToast) { return; } const TOAST_CONFIG = { maxCount: 5, // 最大同时显示数量 baseOffset: 20, // 基础偏移量(px) spacing: 10, // 每个Toast之间的间距 defaultDuration: 3000,// 默认显示时长(ms) animationDuration: 300// 动画过渡时间(ms) }; // 存储活跃的Toast (message -> {element, timer}) const activeToasts = new Map(); // 等待显示的Toast队列 const toastQueue = []; /** * 显示Toast提示 * @param {string} message - 提示内容 * @param {number} duration - 显示时长(ms),可选 * @param {Object} options - 额外选项,可选 * @param {string} options.backgroundColor - 背景颜色 * @param {string} options.color - 文字颜色 */ function showToast(message, duration = TOAST_CONFIG.defaultDuration, options = {}) { // 检查是否已达到最大显示数量 if (activeToasts.size >= TOAST_CONFIG.maxCount) { // 加入队列等待 toastQueue.push({ message, duration, options }); return; } // 检查是否为重复消息 if (activeToasts.has(message)) { return; } // 创建Toast元素 const toast = document.createElement('div'); toast.className = 'tm-toast'; // 合并默认样式和自定义样式 const bgColor = options.backgroundColor || '#333'; const color = options.color || 'white'; toast.style.cssText = ` position: fixed; top: ${TOAST_CONFIG.baseOffset}px; left: 50%; transform: translateX(-50%); background: ${bgColor}; color: ${color}; padding: 10px 20px; border-radius: 5px; z-index: 999999; opacity: 0; transition: all ${TOAST_CONFIG.animationDuration}ms ease; box-shadow: 0 2px 5px rgba(0,0,0,0.2); pointer-events: auto; max-width: 80%; word-wrap: break-word; `; toast.textContent = message; // 添加到文档 const container = document.body || document.documentElement; container.appendChild(toast); // 强制重绘后显示动画 setTimeout(() => { toast.style.opacity = '1'; }, 10); // 记录到活跃列表 const timer = setTimeout(() => { removeToast(message); }, duration); activeToasts.set(message, { element: toast, timer, options }); // 更新所有Toast位置 updateToastPositions(); // 鼠标悬停暂停计时 toast.addEventListener('mouseenter', () => { const toastData = activeToasts.get(message); if (toastData && toastData.timer) { clearTimeout(toastData.timer); toastData.timer = null; toast.style.background = shadeColor(bgColor, 20); // 提亮背景色作为反馈 } }); // 鼠标离开恢复计时 toast.addEventListener('mouseleave', () => { const toastData = activeToasts.get(message); if (toastData && !toastData.timer) { toastData.timer = setTimeout(() => { removeToast(message); }, duration); toast.style.background = bgColor; // 恢复样式 } }); } /** * 移除指定Toast * @param {string} message - 要移除的提示内容 */ function removeToast(message) { const toastData = activeToasts.get(message); if (!toastData) return; const { element, timer } = toastData; if (timer) clearTimeout(timer); // 开始淡出动画 element.style.opacity = '0'; element.style.transform = 'translateX(-50%) translateY(-10px)'; // 动画结束后移除元素 setTimeout(() => { try { element.remove(); } catch (e) { /* 忽略已移除的情况 */ } activeToasts.delete(message); // 更新位置 updateToastPositions(); // 检查队列并显示下一个 if (toastQueue.length > 0) { const nextToast = toastQueue.shift(); showToast(nextToast.message, nextToast.duration, nextToast.options); } }, TOAST_CONFIG.animationDuration); } /** * 更新所有活跃Toast的位置,实现自动堆叠 */ function updateToastPositions() { let currentOffset = TOAST_CONFIG.baseOffset; // 按添加顺序遍历并更新位置 Array.from(activeToasts.values()).forEach(({ element }) => { // 设置新位置 element.style.top = `${currentOffset}px`; // 计算下一个位置(当前元素高度 + 间距) currentOffset += element.offsetHeight + TOAST_CONFIG.spacing; }); } /** * 调整颜色明暗度 * @param {string} color - 十六进制颜色 * @param {number} percent - 百分比,正数变亮,负数变暗 * @returns {string} 调整后的颜色 */ function shadeColor(color, percent) { let R = parseInt(color.substring(1, 3), 16); let G = parseInt(color.substring(3, 5), 16); let B = parseInt(color.substring(5, 7), 16); R = parseInt(R * (100 + percent) / 100); G = parseInt(G * (100 + percent) / 100); B = parseInt(B * (100 + percent) / 100); R = (R < 255) ? R : 255; G = (G < 255) ? G : 255; B = (B < 255) ? B : 255; R = Math.round(R); G = Math.round(G); B = Math.round(B); const RR = ((R.toString(16).length === 1) ? "0" + R.toString(16) : R.toString(16)); const GG = ((G.toString(16).length === 1) ? "0" + G.toString(16) : G.toString(16)); const BB = ((B.toString(16).length === 1) ? "0" + B.toString(16) : B.toString(16)); return `#${RR}${GG}${BB}`; } /** * 清除所有toast */ function clearAllToasts() { // 清除活跃的toast Array.from(activeToasts.keys()).forEach(message => { removeToast(message); }); // 清空队列 toastQueue.length = 0; } /** * 配置toast全局参数 * @param {Object} config - 配置对象 */ function configToast(config) { Object.assign(TOAST_CONFIG, config); } // 暴露公共API window.MonkeyToast = { show: showToast, remove: removeToast, clearAll: clearAllToasts, config: configToast }; })(window);