您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Greasy Fork is available in English.
toast组件
当前为
此脚本不应直接安装。它是供其他脚本使用的外部库,要使用该库请加入元指令 // @require https://update.greasyfork.icu/scripts/548898/1657491/Toast%E7%BB%84%E4%BB%B6%E6%A8%A1%E5%9D%97.js
// ==UserScript== // @name Toast组件模块 // @namespace http://tampermonkey.net/ // @version 1.0.2 // @description toast组件 // @author Lulu // @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: '#f5f5f5', // 默认浅灰背景(柔和不抢镜,适配各类页面) text: '#333333', // 深灰文字(对比度充足,阅读清晰) border: '1px solid #e0e0e0',// 细边框(增强边界感,避免与页面融合) hoverBackground: '#e8e8e8',// 悬停浅灰加深(轻微变化,交互反馈清晰) hoverText: '#222222', // 悬停文字稍深(辅助强化交互感知) 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.hoverBackground - 悬停背景色 * @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 hoverBgColor = options.hoverBackground || COLORS.default.hoverBackground; const hoverOpacity = options.hoverOpacity ?? COLORS.default.hoverOpacity; // 使用空值合并运算符处理0的情况 // 创建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.15); pointer-events: auto; max-width: 80%; word-wrap: break-word; font-size: 14px; `; 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, // 保存原始背景色用于恢复 hoverBg: hoverBgColor, // 保存悬停背景色 hoverOpacity: hoverOpacity // 保存悬停透明度 }); // 更新所有Toast位置 updateToastPositions(); // 鼠标悬停暂停计时并改变样式 toast.addEventListener('mouseenter', () => { const toastData = activeToasts.get(message); if (toastData && toastData.timer) { clearTimeout(toastData.timer); toastData.timer = null; // 应用hover样式:浅灰色背景 + 30%透明度 toast.style.background = toastData.hoverBg; 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.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 // 新增颜色配置API }; })(window);