此腳本不應該直接安裝,它是一個供其他腳本使用的函式庫。欲使用本函式庫,請在腳本 metadata 寫上: // @require https://update.gf.qytechs.cn/scripts/548898/1657505/Toast%E7%BB%84%E4%BB%B6%E6%A8%A1%E5%9D%97.js
你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式
你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式
你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式
你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式
你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式
你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式
(我已經安裝了使用者樣式管理器,讓我安裝!)
// ==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);