知乎多功能标题栏隐藏器

【可配置开关】智能隐藏知乎文章页和问题页的悬浮标题栏。文章页移除class,问题页清空标题内容,提供沉浸式阅读。可在油猴菜单中单独控制。

// ==UserScript==
// @name         知乎多功能标题栏隐藏器
// @namespace    http://tampermonkey.net/
// @version      2.0
// @description  【可配置开关】智能隐藏知乎文章页和问题页的悬浮标题栏。文章页移除class,问题页清空标题内容,提供沉浸式阅读。可在油猴菜单中单独控制。
// @author       inspirewind
// @match        https://zhuanlan.zhihu.com/p/*
// @match        https://www.zhihu.com/question/*
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_registerMenuCommand
// @license      MIT
// @icon         https://www.google.com/s2/favicons?sz=64&domain=zhihu.com
// ==/UserScript==


(function() {
    'use strict';

    // --- 配置管理 ---

    const CONFIG_KEYS = {
        hideArticle: 'config_hide_article_header',
        hideQuestion: 'config_hide_question_header'
    };

    // 读取配置,如果配置不存在,则默认为 true (隐藏)
    let hideArticleHeader = GM_getValue(CONFIG_KEYS.hideArticle, true);
    let hideQuestionHeader = GM_getValue(CONFIG_KEYS.hideQuestion, true);

    // --- 注册油猴菜单 ---

    // 动态更新菜单项的文本,用✅和❌表示当前状态
    const updateMenu = () => {
        // 为了确保菜单能动态刷新,我们需要一个唯一的key来注册,这里用脚本名+key
        const menuKeyArticle = `article_menu_toggle_${Math.random()}`;
        const menuKeyQuestion = `question_menu_toggle_${Math.random()}`;

        GM_registerMenuCommand(
            `${hideArticleHeader ? '✅' : '❌'} 切换隐藏文章页标题`,
            () => {
                // 点击时,反转设置并保存
                hideArticleHeader = !hideArticleHeader;
                GM_setValue(CONFIG_KEYS.hideArticle, hideArticleHeader);
                // 刷新页面以立即应用设置
                location.reload();
            },
            menuKeyArticle
        );

        GM_registerMenuCommand(
            `${hideQuestionHeader ? '✅' : '❌'} 切换隐藏问题页标题`,
            () => {
                hideQuestionHeader = !hideQuestionHeader;
                GM_setValue(CONFIG_KEYS.hideQuestion, hideQuestionHeader);
                location.reload();
            },
            menuKeyQuestion
        );
    };

    // 初始化菜单
    updateMenu();


    // --- 核心逻辑 ---

    /**
     * 创建一个MutationObserver来监视指定元素的class变化
     * @param {string} selector - 要监视的元素选择器
     * @param {string} className - 要移除的class名称
     */
    const observeAndRemoveClass = (selector, className) => {
        const targetNode = document.querySelector(selector);
        if (!targetNode) {
            // 如果页面上没有这个元素,就直接返回
            console.log(`[知乎标题栏隐藏器] 未找到目标元素: ${selector}`);
            return;
        }

        const observer = new MutationObserver((mutationsList) => {
            for (const mutation of mutationsList) {
                if (mutation.type === 'attributes' && mutation.attributeName === 'class') {
                    if (targetNode.classList.contains(className)) {
                        targetNode.classList.remove(className);
                        // console.log(`已移除 ${selector} 的 ${className} class。`);
                    }
                }
            }
        });

        observer.observe(targetNode, { attributes: true });
        console.log(`[知乎标题栏隐藏器] 已开始监视 ${selector}`);
    };

    // --- 页面路由:根据当前URL决定执行哪个逻辑 ---

    // 使用 try...catch 避免在某些特殊页面因找不到元素而报错
    try {
        const currentUrl = window.location.href;

        // 1. 如果是文章页 (zhuanlan.zhihu.com/p/...)
        if (currentUrl.includes('zhuanlan.zhihu.com/p/')) {
            if (hideArticleHeader) {
                console.log("[知乎标题栏隐藏器] 文章页模式启动");
                // 文章页是 .PageHeader 和 is-shown
                observeAndRemoveClass('.PageHeader', 'is-shown');
            } else {
                 console.log("[知乎标题栏隐藏器] 文章页标题栏已设置为显示。");
            }
        }

        // 2. 如果是问题页 (zhihu.com/question/...)
        else if (currentUrl.includes('www.zhihu.com/question/')) {
            if (hideQuestionHeader) {
                console.log("[知乎标题栏隐藏器] 问题页模式启动");
                 // 问题页也是 .PageHeader 和 is-shown
                observeAndRemoveClass('.PageHeader', 'is-shown');
            } else {
                 console.log("[知乎标题栏隐藏器] 问题页标题栏已设置为显示。");
            }
        }
    } catch (error) {
        console.error('[知乎标题栏隐藏器] 脚本执行出错:', error);
    }

})();