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.04
// @match        *://*/*
// @run-at document-start
// @grant  GM_addStyle
// @grant  GM_getValue
// @grant  GM_setValue
// @grant  GM_registerMenuCommand
// @namespace http://greasyfork.icu/users/22620
// @description 全局修改字体
// ==/UserScript==

(function() {
    'use strict';

    // --- 默认配置项 ---
    const DEFAULT_FONT = '"MiSans"';
    // 默认排除常见的图标、符号和特殊元素
    const DEFAULT_EXCLUSIONS = 'i, [class*="ico"], [class*="fa"]';
    
    // --- GM 存储的 Key ---
    const STORAGE_KEY_FONT = 'config_my_new_font';
    const STORAGE_KEY_EXCLUSIONS = 'config_icon_exclusion_selectors';

    // --- 内部变量 (由配置加载) ---
    let MY_NEW_FONT;
    let ICON_EXCLUSION_SELECTORS_ARRAY;
    let phaseOneStyleElement = null;

    // --- GM 配置函数 ---

    /**
     * 从 GM 存储中加载配置,如果没有则使用默认值。
     */
    const loadConfig = () => {
        // 从存储中读取字体
        MY_NEW_FONT = GM_getValue(STORAGE_KEY_FONT, DEFAULT_FONT);

        // 从存储中读取排除选择器字符串
        const storedExclusionsString = GM_getValue(STORAGE_KEY_EXCLUSIONS, DEFAULT_EXCLUSIONS);
        
        // 将字符串分割成数组,并去除空格和空元素
        ICON_EXCLUSION_SELECTORS_ARRAY = storedExclusionsString
            .split(',')
            .map(s => s.trim())
            .filter(s => s.length > 0);
        
        console.log(`⚙️ 已加载配置: 字体: ${MY_NEW_FONT}, 排除项数量: ${ICON_EXCLUSION_SELECTORS_ARRAY.length}`);
    };
    
    // --- 菜单命令实现 ---

    /**
     * 弹出配置字体名称的对话框。
     */
    const configFontName = () => {
        const currentFont = GM_getValue(STORAGE_KEY_FONT, DEFAULT_FONT);

        const newFont = prompt(
            '请输入新的字体名称 (用逗号分隔,例如: "MiSans", system-ui, sans-serif)',
            currentFont
        );

        if (newFont !== null) {
            GM_setValue(STORAGE_KEY_FONT, newFont.trim());
            alert('字体名称已保存!请刷新页面以应用新设置。');
        }
    };
    
    /**
     * 弹出配置排除元素列表的对话框。
     */
    const configExclusionList = () => {
        const currentExclusions = GM_getValue(STORAGE_KEY_EXCLUSIONS, DEFAULT_EXCLUSIONS);
        
        const newExclusions = prompt(
            '请输入新的排除元素选择器 (用逗号分隔,用于保护图标字体等,例如: i, [class*="ico"])',
            currentExclusions
        );
        
        if (newExclusions !== null) {
            GM_setValue(STORAGE_KEY_EXCLUSIONS, newExclusions.trim());
            alert('排除列表已保存!请刷新页面以应用新设置。');
        }
    };

    /**
     * 恢复所有配置为默认值。
     */
    const resetConfig = () => {
        if (confirm('确定要将字体配置和排除列表都恢复为默认值吗?')) {
            GM_setValue(STORAGE_KEY_FONT, DEFAULT_FONT);
            GM_setValue(STORAGE_KEY_EXCLUSIONS, DEFAULT_EXCLUSIONS);
            alert('配置已恢复为默认值!请刷新页面以应用。');
        }
    };

    /**
     * 注册配置菜单命令。
     */
    const registerMenu = () => {
        GM_registerMenuCommand('🖋️ 配置字体名称', configFontName);
        GM_registerMenuCommand('❌ 配置排除元素列表', configExclusionList);
        GM_registerMenuCommand('🗑️ 恢复默认设置', resetConfig); 
    };

    // --- CSS 注入逻辑 (不变) ---
    
    const generateCSS = (fontFamily) => {
        const ICON_EXCLUSION_SELECTOR_STRING = ICON_EXCLUSION_SELECTORS_ARRAY
            .map(selector => `:not(${selector})`)
            .join('');

        return `
            /* 全局选择器,排除图标和特殊符号元素 */
            *${ICON_EXCLUSION_SELECTOR_STRING} {
                font-family: ${fontFamily} !important;
            }
        `;
    };

    const injectPhaseOneCSS = (newFontFamily) => {
        const cssContent = generateCSS(newFontFamily);
        phaseOneStyleElement = GM_addStyle(cssContent); 
        console.log(`⏱️ 阶段一:立即注入初始字体: ${newFontFamily}`);
    };

    const runPhaseTwo = async (newFontFamily) => {
        try {
            await document.fonts.ready;
            const protectedFontNames = new Set();
            
            document.fonts.forEach(fontFace => {
                protectedFontNames.add(`"${fontFace.family.replace(/"/g, '')}"`); 
            });

            const protectedFontFamily = Array.from(protectedFontNames).join(', ');
            let finalFontFamily = protectedFontFamily 
                ? `${newFontFamily}, ${protectedFontFamily}` 
                : `${newFontFamily}`;
            
            const cssContentFinal = generateCSS(finalFontFamily);
            
            // 尝试更新已注入的 <style> 元素
            if (phaseOneStyleElement && typeof phaseOneStyleElement.textContent !== 'undefined') {
                phaseOneStyleElement.textContent = cssContentFinal;
                console.log("✅ 阶段二:全局字体已最终更新并保护原有字体:", finalFontFamily);
            } else {
                // 备用:再次注入
                GM_addStyle(cssContentFinal); 
                console.log("✅ 阶段二:全局字体已最终更新并保护原有字体 (通过再次注入):", finalFontFamily);
            }

        } catch (error) {
            console.error("⚠️ 字体加载或识别过程中出错,将保持初始字体设置:", error);
        }
    };

    // --- 脚本主执行流程 ---
    
    // 1. 注册 Tampermonkey 菜单命令
    registerMenu();

    // 2. 加载用户配置
    loadConfig();

    // 3. 运行字体注入的两个阶段
    injectPhaseOneCSS(MY_NEW_FONT); 
    runPhaseTwo(MY_NEW_FONT);
    
})();