小红书首页简洁模式

在小红书首页添加模式切换功能,支持原生模式和简洁模式切换。简洁模式在首页移除其余元素仅显示搜索框。

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey, Greasemonkey или Violentmonkey.

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

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Violentmonkey.

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Userscripts.

За да инсталирате скрипта, трябва да инсталирате разширение като Tampermonkey.

За да инсталирате този скрипт, трябва да имате инсталиран скриптов мениджър.

(Вече имам скриптов мениджър, искам да го инсталирам!)

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

(Вече имам инсталиран мениджър на стиловете, искам да го инсталирам!)

// ==UserScript==
// @name         小红书首页简洁模式
// @namespace    http://tampermonkey.net/
// @version      1.0
// @description  在小红书首页添加模式切换功能,支持原生模式和简洁模式切换。简洁模式在首页移除其余元素仅显示搜索框。
// @author       kamaboko
// @match        https://www.xiaohongshu.com/explore*
// @match        https://www.xiaohongshu.com/explore/*
// @license      GPL-3.0 License
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    // 等待页面加载完成
    function waitForElement(selector, timeout = 10000) {
        return new Promise((resolve, reject) => {
            const element = document.querySelector(selector);
            if (element) {
                resolve(element);
                return;
            }

            const observer = new MutationObserver((mutations, obs) => {
                const element = document.querySelector(selector);
                if (element) {
                    obs.disconnect();
                    resolve(element);
                }
            });

            observer.observe(document.body, {
                childList: true,
                subtree: true
            });

            setTimeout(() => {
                observer.disconnect();
                reject(new Error(`Element ${selector} not found within ${timeout}ms`));
            }, timeout);
        });
    }

    // 创建模式切换按钮
    function createModeToggleButton() {
        const buttonContainer = document.createElement('div');
        buttonContainer.style.cssText = `
            position: fixed;
            top: 20px;
            right: 20px;
            z-index: 10000;
            background: #fff;
            border: 2px solid #ff2442;
            border-radius: 8px;
            padding: 8px 12px;
            box-shadow: 0 4px 12px rgba(0,0,0,0.15);
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
        `;

        const button = document.createElement('button');
        button.textContent = '原生模式';
        button.style.cssText = `
            background: #ff2442;
            color: white;
            border: none;
            border-radius: 4px;
            padding: 6px 12px;
            cursor: pointer;
            font-size: 14px;
            font-weight: 500;
            transition: all 0.2s ease;
        `;

        button.addEventListener('mouseenter', () => {
            button.style.background = '#e61e3c';
        });

        button.addEventListener('mouseleave', () => {
            button.style.background = '#ff2442';
        });

        buttonContainer.appendChild(button);
        document.body.appendChild(buttonContainer);

        return { button, container: buttonContainer };
    }

    // 获取需要隐藏的元素选择器
    function getElementsToHide() {
        return [
            // 导航栏相关
            'nav',
            '.nav',
            '.navbar',
            '.header',
            '.top-bar',
            // 侧边栏
            '.side-bar',
            '.side-nav',
            '.dropdown-nav',
            '.left-panel',
            // 推荐内容区域
            '.recommend',
            '.feed',
            '.content-feed',
            '.explore-feed',
            // 其他可能的内容区域
            '.main-content:not(.search-container)',
            '.content-area:not(.search-container)',
            // 底部
            '.footer',
            '.bottom-nav'
        ];
    }

    // 隐藏/显示元素
    function toggleElements(hide, elementsToHide) {
        elementsToHide.forEach(selector => {
            const elements = document.querySelectorAll(selector);
            elements.forEach(element => {
                if (hide) {
                    element.style.display = 'none';
                } else {
                    element.style.display = '';
                }
            });
        });
    }

    // 查找并保留搜索框
    function preserveSearchBox() {
        // 为mask-paper类添加样式,让它在屏幕中间显示
        const maskPaperElements = document.querySelectorAll('.mask-paper');
        maskPaperElements.forEach(element => {
            element.style.cssText = `
                position: fixed !important;
                top: 50% !important;
                left: 50% !important;
                transform: translate(-50%, -50%) !important;
                z-index: 9999 !important;
                display: flex !important;
                flex-direction: column !important;
                align-items: center !important;
                gap: 10px !important;
                width: auto !important;
                height: auto !important;
            `;
        });

        // 为logo图标添加样式,让它显示在上方
        const logoElements = document.querySelectorAll('.header-logo');
        logoElements.forEach(element => {
            element.style.cssText = `
                width: 120px !important;
                height: auto !important;
                pointer-events: none !important;
                order: -1 !important;
            `;
        });

        // 为搜索框容器添加样式,确保它在下方且居中
        const inputBoxElements = document.querySelectorAll('.input-box');
        inputBoxElements.forEach(element => {
            element.style.cssText = `
                display: flex !important;
                align-items: center !important;
                justify-content: center !important;
                width: auto !important;
                height: auto !important;
                order: 1 !important;
                position: relative !important;
                min-height: 50px !important;
            `;
        });

        // 为搜索框添加样式
        const searchInputElements = document.querySelectorAll('.search-input');
        searchInputElements.forEach(element => {
            if (element.tagName === 'INPUT' && element.type === 'text') {
                element.style.cssText = `
                    width: 500px !important;
                    height: 50px !important;
                    border-radius: 25px !important;
                    padding: 0 20px !important;
                    outline: none !important;
                `;
            }
        });

        // 为搜索按钮添加样式,确保它在搜索框中且生效
        const inputButtonElements = document.querySelectorAll('.input-button');
        inputButtonElements.forEach(element => {
            element.style.cssText = `
                position: absolute !important;
                right: 10px !important;
                top: 50% !important;
                transform: translateY(-50%) !important;
                z-index: 10000 !important;
                pointer-events: auto !important;
                cursor: pointer !important;
            `;
        });

        // 修复下拉菜单的位置,确保它在搜索框下方显示且保持原样
        const dropdownElements = document.querySelectorAll('[class*="sug-pad"], [class*="suggestion"], [class*="autocomplete"]');
        dropdownElements.forEach(element => {
            element.style.cssText = `
                position: absolute !important;
                top: 100% !important;
                left: 0 !important;
                width: 100% !important;
                z-index: 10001 !important;
                transform: none !important;
            `;
        });

        // 特别处理sug-pad sug-container-wrapper类的下拉菜单
        const sugPadElements = document.querySelectorAll('.sug-container-wrapper.sug-pad');
        sugPadElements.forEach(element => {
            element.style.cssText = `
                position: absolute !important;
                top: 100% !important;
                left: 0 !important;
                width: 100% !important;
                z-index: 10001 !important;
                transform: none !important;
                margin-top: 5px !important;
            `;
        });

        // 创建MutationObserver来监听下拉菜单的动态创建
        const dropdownObserver = new MutationObserver((mutations) => {
            mutations.forEach((mutation) => {
                if (mutation.type === 'childList') {
                    mutation.addedNodes.forEach((node) => {
                        if (node.nodeType === Node.ELEMENT_NODE) {
                            // 检查新添加的元素是否是下拉菜单
                            if (node.classList && (node.classList.contains('sug-pad') || node.classList.contains('sug-container-wrapper'))) {
                                applyDropdownStyles(node);
                            }
                            // 检查新添加元素的子元素
                            const dropdowns = node.querySelectorAll('[class*="sug-pad"], [class*="sug-container-wrapper"]');
                            dropdowns.forEach(dropdown => applyDropdownStyles(dropdown));
                        }
                    });
                }
            });
        });

        // 应用下拉菜单样式的函数
        function applyDropdownStyles(element) {
            element.style.setProperty('position', 'absolute', 'important');
            element.style.setProperty('top', '100%', 'important');
            element.style.setProperty('left', '0', 'important');
            element.style.setProperty('width', '100%', 'important');
            element.style.setProperty('z-index', '10001', 'important');
            element.style.setProperty('transform', 'none', 'important');
            element.style.setProperty('margin-top', '5px', 'important');
        }

        // 开始监听DOM变化
        dropdownObserver.observe(document.body, {
            childList: true,
            subtree: true
        });

        // 将observer保存到全局,以便在恢复时停止监听
        window.xiaohongshuDropdownObserver = dropdownObserver;
    }

    // 恢复搜索框原始样式的函数
    function restoreSearchBoxOriginalStyle() {
        // 恢复mask-paper的原始样式
        const maskPaperElements = document.querySelectorAll('.mask-paper');
        maskPaperElements.forEach(element => {
            element.style.cssText = '';
        });

        // 恢复logo的原始样式
        const logoElements = document.querySelectorAll('.header-logo');
        logoElements.forEach(element => {
            element.style.cssText = '';
        });

        // 恢复搜索框的原始样式
        const searchInputElements = document.querySelectorAll('.search-input');
        searchInputElements.forEach(element => {
            if (element.tagName === 'INPUT' && element.type === 'text') {
                element.style.cssText = '';
            }
        });

        // 恢复input-box的原始样式
        const inputBoxElements = document.querySelectorAll('.input-box');
        inputBoxElements.forEach(element => {
            element.style.cssText = '';
        });

        // 恢复input-button的原始样式
        const inputButtonElements = document.querySelectorAll('.input-button');
        inputButtonElements.forEach(element => {
            element.style.cssText = '';
        });

        // 恢复下拉菜单的原始样式
        const dropdownElements = document.querySelectorAll('[class*="sug-pad"], [class*="suggestion"], [class*="autocomplete"]');
        dropdownElements.forEach(element => {
            element.style.cssText = '';
        });

        // 特别恢复sug-pad sug-container-wrapper类的下拉菜单
        const sugPadElements = document.querySelectorAll('.sug-container-wrapper.sug-pad');
        sugPadElements.forEach(element => {
            element.style.cssText = '';
        });

        // 停止下拉菜单的MutationObserver监听
        if (window.xiaohongshuDropdownObserver) {
            window.xiaohongshuDropdownObserver.disconnect();
            window.xiaohongshuDropdownObserver = null;
        }
    }

    // 主函数
    async function init() {
        try {
            // 等待页面主要内容加载
            await waitForElement('body');

            // 创建模式切换按钮
            const { button, container } = createModeToggleButton();

            let isNativeMode = true;
            const elementsToHide = getElementsToHide();

            // 检查当前URL,如果不是explore页面,自动恢复到原生模式
            function checkAndRestoreMode() {
                const currentUrl = window.location.href;
                if (!currentUrl.includes('/explore')) {
                    // 不在explore页面,自动恢复到原生模式
                    isNativeMode = true;
                    button.textContent = '原生模式';
                    button.style.background = '#ff2442';
                    toggleElements(false, elementsToHide);

                    // 恢复搜索框原始位置
                    const searchElements = document.querySelectorAll('input[type="search"], input[placeholder*="搜索"], .search-input');
                    searchElements.forEach(element => {
                        const container = element.closest('.search-container') || element.closest('form') || element.parentElement;
                        if (container) {
                            container.style.cssText = '';
                        }
                    });

                    // 恢复input-box的原始位置
                    const inputBoxElements = document.querySelectorAll('.input-box');
                    inputBoxElements.forEach(element => {
                        element.style.cssText = '';
                    });

                    // 恢复搜索框、logo等的原始样式
                    restoreSearchBoxOriginalStyle();
                } else {
                    // 在explore页面,检查是否是分享链接
                    const urlParams = new URLSearchParams(window.location.search);
                    const isShareLink = urlParams.has('share_from_user_hidden') ||
                                       urlParams.has('share_id') ||
                                       urlParams.has('xsec_source') ||
                                       urlParams.has('type') ||
                                       urlParams.has('author_share') ||
                                       urlParams.has('xhsshare');

                    if (isShareLink) {
                        // 分享链接保持原生模式
                        isNativeMode = true;
                        button.textContent = '原生模式';
                        button.style.background = '#ff2442';
                        toggleElements(false, elementsToHide);
                        restoreSearchBoxOriginalStyle();
                        localStorage.setItem('xiaohongshuMode', 'original');
                    } else {
                        // 普通explore页面,检查用户偏好设置
                        const userPreference = localStorage.getItem('xiaohongshuMode');
                        if (userPreference === 'minimal' || userPreference === null) {
                            // 默认使用简洁模式,或者用户之前选择过简洁模式
                            isNativeMode = false;
                            button.textContent = '简洁模式';
                            button.style.background = '#28a745';
                            toggleElements(true, elementsToHide);
                            preserveSearchBox();
                            localStorage.setItem('xiaohongshuMode', 'minimal');
                        }
                    }
                }
            }

            // 添加点击事件
            button.addEventListener('click', () => {
                // 检查是否在explore页面
                if (!window.location.href.includes('/explore')) {
                    alert('此功能仅在首页可用');
                    return;
                }

                // 检查是否是分享链接
                const urlParams = new URLSearchParams(window.location.search);
                const isShareLink = urlParams.has('share_from_user_hidden') ||
                                   urlParams.has('share_id') ||
                                   urlParams.has('xsec_source') ||
                                   urlParams.has('type') ||
                                   urlParams.has('author_share') ||
                                   urlParams.has('xhsshare');

                if (isShareLink) {
                    alert('分享链接页面不支持模式切换,将保持原生模式');
                    return;
                }

                isNativeMode = !isNativeMode;

                if (isNativeMode) {
                    button.textContent = '原生模式';
                    button.style.background = '#ff2442';
                    toggleElements(false, elementsToHide);
                    // 恢复搜索框原始位置
                    const searchElements = document.querySelectorAll('input[type="search"], input[placeholder*="搜索"], .search-input');
                    searchElements.forEach(element => {
                        const container = element.closest('.search-container') || element.closest('form') || element.parentElement;
                        if (container) {
                            container.style.cssText = '';
                        }
                    });

                    // 恢复input-box的原始位置
                    const inputBoxElements = document.querySelectorAll('.input-box');
                    inputBoxElements.forEach(element => {
                        element.style.cssText = '';
                    });

                    // 恢复搜索框、logo等的原始样式
                    restoreSearchBoxOriginalStyle();

                    // 保存用户偏好
                    localStorage.setItem('xiaohongshuMode', 'original');
                } else {
                    button.textContent = '简洁模式';
                    button.style.background = '#28a745';
                    toggleElements(true, elementsToHide);
                    preserveSearchBox();

                    // 保存用户偏好
                    localStorage.setItem('xiaohongshuMode', 'minimal');
                }
            });

            // 监听URL变化
            let currentUrl = window.location.href;
            const urlObserver = new MutationObserver(() => {
                if (window.location.href !== currentUrl) {
                    currentUrl = window.location.href;
                    checkAndRestoreMode();
                }
            });

            // 监听页面内容变化(包括pushState等)
            urlObserver.observe(document.body, {
                childList: true,
                subtree: true
            });

            // 监听popstate事件(浏览器前进后退)
            window.addEventListener('popstate', checkAndRestoreMode);

            // 重写pushState和replaceState方法以监听URL变化
            const originalPushState = history.pushState;
            const originalReplaceState = history.replaceState;

            history.pushState = function(...args) {
                originalPushState.apply(this, args);
                setTimeout(checkAndRestoreMode, 100);
            };

            history.replaceState = function(...args) {
                originalReplaceState.apply(this, args);
                setTimeout(checkAndRestoreMode, 100);
            };

            // 初始化时检查并应用模式
            checkAndRestoreMode();
        } catch (error) {
            console.error('加载失败:', error);
        }
    }

    // 页面加载完成后初始化
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', init);
    } else {
        init();
    }
})();