🎉 欢迎访问GreasyFork.Org 镜像站!本镜像站由公众号【爱吃馍】搭建,用于分享脚本。联系邮箱📮

Greasy fork 爱吃馍镜像

Toast组件模块

toast组件

As of 2025-09-09. See the latest version.

This script should not be not be installed directly. It is a library for other scripts to include with the meta directive // @require https://update.greasyfork.org/scripts/548898/1657484/Toast%E7%BB%84%E4%BB%B6%E6%A8%A1%E5%9D%97.js

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

🚀 安装遇到问题?关注公众号获取帮助

公众号二维码

扫码关注【爱吃馍】

回复【脚本】获取最新教程和防失联地址

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

🚀 安装遇到问题?关注公众号获取帮助

公众号二维码

扫码关注【爱吃馍】

回复【脚本】获取最新教程和防失联地址

// ==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: '#4a4a4a',    // 默认深灰色背景
            text: '#ffffff',          // 白色文字
            hoverBackground: '#888888',// 悬停时浅灰色背景
            hoverOpacity: 0.7         // 悬停时透明度(30%透明)
        }
    };

    // 存储活跃的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);