Greasy Fork

Greasy Fork is available in English.

全局字体

全局修改字体

当前为 2025-12-07 提交的版本,查看 最新版本

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

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

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name        全局字体
// @author      gemini
// @version     1.07
// @match       *://*/*
// @run-at      document-start
// @grant       GM_addStyle
// @grant       GM_getValue
// @grant       GM_setValue
// @grant       GM_registerMenuCommand
// @grant       GM_unregisterMenuCommand
// @namespace   http://greasyfork.icu/users/22620
// @description 全局修改字体
// ==/UserScript==

(function() {
    'use strict';

    // --- 配置常量 ---
    const DEFAULT_CONFIG = {
        font: '微软雅黑',
        exclusions: 'i, [class*="ico"], [class*="fa"], [class*="emoji"]',
        enabled: true
    };
    
    const STORAGE_KEYS = {
        font: 'config_my_new_font',
        exclusions: 'config_icon_exclusion_selectors',
        enabled: 'config_font_enabled'
    };

    // --- 状态管理 ---
    class FontManager {
        constructor() {
            this.config = {
                font: DEFAULT_CONFIG.font,
                exclusions: DEFAULT_CONFIG.exclusions,
                enabled: DEFAULT_CONFIG.enabled
            };
            
            this.styleElement = null;
            this.configUpdateCallbacks = [];
        }

        // 加载配置
        loadConfig() {
            this.config.font = GM_getValue(STORAGE_KEYS.font, DEFAULT_CONFIG.font);
            this.config.enabled = GM_getValue(STORAGE_KEYS.enabled, DEFAULT_CONFIG.enabled);
            
            const storedExclusions = GM_getValue(STORAGE_KEYS.exclusions, DEFAULT_CONFIG.exclusions);
            this.config.exclusions = storedExclusions;
            
            console.log(`⚙️ 配置加载: 字体=${this.config.font}, 启用=${this.config.enabled}, 排除项=${storedExclusions}`);
        }

        // 保存配置
        saveConfig() {
            GM_setValue(STORAGE_KEYS.font, this.config.font);
            GM_setValue(STORAGE_KEYS.exclusions, this.config.exclusions);
            GM_setValue(STORAGE_KEYS.enabled, this.config.enabled);
        }

        // 添加配置更新回调
        onConfigUpdate(callback) {
            this.configUpdateCallbacks.push(callback);
        }

        // 触发配置更新回调
        triggerConfigUpdate() {
            this.configUpdateCallbacks.forEach(callback => callback(this.config));
        }

        // 生成排除选择器字符串
        getExclusionSelector() {
            return this.config.exclusions
                .split(',')
                .map(s => s.trim())
                .filter(Boolean)  // 使用 Boolean 函数过滤空值
                .map(selector => `:not(${selector})`)
                .join('');
        }

        // 生成 CSS
        generateCSS(fontFamily = this.config.font) {
            const exclusionSelector = this.getExclusionSelector();
            return `
                /* 全局字体修改 - ${new Date().toLocaleTimeString()} */
                *${exclusionSelector} {
                    font-family: ${fontFamily} !important;
                }
            `;
        }

        // 注入 CSS
        injectCSS(css) {
            this.removeCSS();
            this.styleElement = GM_addStyle(css);
            return this.styleElement;
        }

        // 移除 CSS
        removeCSS() {
            if (this.styleElement?.parentNode) {
                this.styleElement.parentNode.removeChild(this.styleElement);
                this.styleElement = null;
            }
        }

        // 应用字体(两个阶段)
        async applyFont() {
            if (!this.config.enabled) {
                this.removeCSS();
                return;
            }

            // 阶段一:立即注入
            const initialCSS = this.generateCSS(this.config.font);
            this.injectCSS(initialCSS);
            console.log(`⏱️ 阶段一:注入初始字体: ${this.config.font}`);

            // 阶段二:等待字体加载完成后更新
            try {
                await document.fonts?.ready;
                
                const protectedFonts = new Set();
                document.fonts?.forEach?.(fontFace => {
                    const fontFamily = fontFace.family.replace(/"/g, '');
                    if (fontFamily) protectedFonts.add(`"${fontFamily}"`);
                });

                const protectedFontFamily = [...protectedFonts].join(', ');
                const finalFontFamily = protectedFontFamily 
                    ? `${this.config.font}, ${protectedFontFamily}`
                    : this.config.font;

                const finalCSS = this.generateCSS(finalFontFamily);
                this.injectCSS(finalCSS);
                console.log(`✅ 阶段二:最终字体: ${finalFontFamily}`);
            } catch (error) {
                console.warn('⚠️ 字体加载出错,使用初始字体:', error);
            }
        }

        // 更新配置并重新应用
        updateConfig(updates) {
            Object.assign(this.config, updates);
            this.saveConfig();
            this.applyFont();
            this.triggerConfigUpdate();
        }

        // 切换启用状态
        toggleEnabled() {
            const newEnabled = !this.config.enabled;
            this.updateConfig({ enabled: newEnabled });
            
            console.log(newEnabled ? '✅ 字体效果已启用' : '❌ 字体效果已禁用');
        }

        // 重置为默认配置
        resetToDefault() {
            if (confirm('确定要将所有配置恢复为默认值吗?')) {
                Object.assign(this.config, DEFAULT_CONFIG);
                this.saveConfig();
                this.applyFont();
                this.triggerConfigUpdate();
                console.log('🔄 配置已重置为默认值');
            }
        }
    }

    // --- 菜单管理 ---
    class MenuManager {
        constructor(fontManager) {
            this.fontManager = fontManager;
            this.commands = new Map();
            
            // 监听配置更新
            this.fontManager.onConfigUpdate(() => this.updateMenu());
        }

        // 注册所有菜单命令
        registerAll() {
            this.registerToggleCommand();
            this.registerFontConfigCommand();
            this.registerExclusionsConfigCommand();
            this.registerResetCommand();
        }

        // 注册切换命令
        registerToggleCommand() {
            const label = this.fontManager.config.enabled 
                ? '❌ 禁用字体效果' 
                : '✅ 启用字体效果';
            
            const id = GM_registerMenuCommand(label, () => {
                this.fontManager.toggleEnabled();
            });
            
            this.commands.set('toggle', id);
        }

        // 注册字体配置命令
        registerFontConfigCommand() {
            const id = GM_registerMenuCommand('🖋️ 配置字体名称', () => {
                const currentFont = this.fontManager.config.font;
                const newFont = prompt(
                    '请输入新的字体名称 (用逗号分隔,例如: "MiSans", system-ui, sans-serif)',
                    currentFont
                );

                if (newFont?.trim()) {
                    this.fontManager.updateConfig({ font: newFont.trim() });
                    alert('字体名称已保存并立即生效!');
                }
            });
            
            this.commands.set('font', id);
        }

        // 注册排除列表配置命令
        registerExclusionsConfigCommand() {
            const id = GM_registerMenuCommand('🚫 配置排除元素列表', () => {
                const currentExclusions = this.fontManager.config.exclusions;
                const newExclusions = prompt(
                    '请输入新的排除元素选择器 (用逗号分隔,用于保护图标字体等,例如: i, [class*="ico"])',
                    currentExclusions
                );

                if (newExclusions !== null) {
                    this.fontManager.updateConfig({ exclusions: newExclusions.trim() });
                    alert('排除列表已保存并立即生效!');
                }
            });
            
            this.commands.set('exclusions', id);
        }

        // 注册重置命令
        registerResetCommand() {
            const id = GM_registerMenuCommand('🗑️ 恢复默认设置', () => {
                this.fontManager.resetToDefault();
            });
            
            this.commands.set('reset', id);
        }

        // 更新所有菜单
        updateMenu() {
            // 重新注册所有菜单以更新标签
            this.commands.forEach(id => {
                try {
                    GM_unregisterMenuCommand(id);
                } catch (e) {
                    // 忽略未注册的命令
                }
            });
            
            this.commands.clear();
            this.registerAll();
        }
    }

    // --- 主执行流程 ---
    const fontManager = new FontManager();
    const menuManager = new MenuManager(fontManager);

    // 初始化
    fontManager.loadConfig();
    menuManager.registerAll();

    // 根据启用状态决定是否应用字体
    if (fontManager.config.enabled) {
        // 延迟执行以确保 DOM 已加载
        const applyFont = () => fontManager.applyFont();
        
        if (document.readyState === 'loading') {
            document.addEventListener('DOMContentLoaded', applyFont);
        } else {
            applyFont();
        }
    }

    // 暴露到全局便于调试
    window.GlobalFontManager = fontManager;
    console.log('🎨 全局字体脚本已加载');
})();