您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Greasy Fork is available in English.
可被其他油猴脚本引用的toast提示组件
此脚本不应直接安装。它是供其他脚本使用的外部库,要使用该库请加入元指令 // @require https://update.greasyfork.icu/scripts/548898/1657505/Toast%E7%BB%84%E4%BB%B6%E6%A8%A1%E5%9D%97.js
// ==UserScript== // @name Toast组件模块(深色系) // @namespace http://tampermonkey.net/ // @version 1.0 // @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) }; // 深色系颜色配置 const COLORS = { default: { background: 'rgba(45, 45, 45, 0.8)', // 深灰黑色背景(主色调,沉稳不刺眼) text: '#f0f0f0', // 浅灰文字(确保高对比度) border: '1px solid rgba(68, 68, 68, 0.9)',// 深灰边框(增强轮廓) hoverBackground: '#1a1a1a',// 悬停时更深的背景 hoverText: '#ffffff', // 悬停时文字更亮 hoverOpacity: 1 // 完全不透明,确保可读性 } }; // 存储活跃的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 - 文字颜色 * @param {string} options.border - 边框样式 * @param {string} options.hoverBackground - 悬停背景色 * @param {string} options.hoverText - 悬停文字颜色 * @param {number} options.hoverOpacity - 悬停透明度 */ 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; } // 合并默认样式和自定义样式 const bgColor = options.backgroundColor || COLORS.default.background; const textColor = options.color || COLORS.default.text; const border = options.border || COLORS.default.border; const hoverBgColor = options.hoverBackground || COLORS.default.hoverBackground; const hoverTextColor = options.hoverText || COLORS.default.hoverText; const hoverOpacity = options.hoverOpacity ?? COLORS.default.hoverOpacity; // 创建Toast元素 const toast = document.createElement('div'); toast.className = 'tm-toast'; toast.style.cssText = ` position: fixed; top: ${TOAST_CONFIG.baseOffset}px; left: 50%; transform: translateX(-50%); background: ${bgColor}; color: ${textColor}; padding: 10px 20px; border-radius: 5px; z-index: 999999; opacity: 1; transition: all ${TOAST_CONFIG.animationDuration}ms ease; box-shadow: 0 2px 8px rgba(0,0,0,0.3); pointer-events: auto; max-width: 80%; word-wrap: break-word; font-size: 14px; line-height: 1.4; `; toast.textContent = message; // 添加到文档 const container = document.body || document.documentElement; container.appendChild(toast); // 入场动画 setTimeout(() => { toast.style.transform = 'translateX(-50%) translateY(0)'; }, 10); // 记录到活跃列表 const timer = setTimeout(() => { removeToast(message); }, duration); activeToasts.set(message, { element: toast, timer, options, originalBg: bgColor, originalText: textColor, hoverBg: hoverBgColor, hoverText: hoverTextColor, hoverOpacity: hoverOpacity }); // 更新所有Toast位置 updateToastPositions(); // 鼠标悬停暂停计时并改变样式 toast.addEventListener('mouseenter', () => { const toastData = activeToasts.get(message); if (toastData && toastData.timer) { clearTimeout(toastData.timer); toastData.timer = null; // 应用hover样式 toast.style.background = toastData.hoverBg; toast.style.color = toastData.hoverText; toast.style.opacity = toastData.hoverOpacity; } }); // 鼠标离开恢复计时和样式 toast.addEventListener('mouseleave', () => { const toastData = activeToasts.get(message); if (toastData && !toastData.timer) { toastData.timer = setTimeout(() => { removeToast(message); }, duration); // 恢复原始样式 toast.style.background = toastData.originalBg; toast.style.color = toastData.originalText; toast.style.opacity = 1; } }); } /** * 移除指定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; }); } /** * 清除所有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); } /** * 配置全局颜色 * @param {Object} colorConfig - 颜色配置对象 */ function configColors(colorConfig) { Object.assign(COLORS.default, colorConfig); } // 暴露公共API window.MonkeyToast = { show: showToast, remove: removeToast, clearAll: clearAllToasts, config: configToast, configColors: configColors }; })(window);