<?xml version="1.0" encoding="UTF-8"?>
<rdf:RDF
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns="http://purl.org/rss/1.0/"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<channel rdf:about="https://blog.zhifouli.top/index.php/feed/rss/tag/BUG%E4%BF%AE%E5%A4%8D/">
<title>拾星漫记 - BUG修复</title>
<link>https://blog.zhifouli.top/index.php/tag/BUG%E4%BF%AE%E5%A4%8D/</link>
<description></description>
<items>
<rdf:Seq>
<rdf:li resource="https://blog.zhifouli.top/index.php/archives/27/"/>
<rdf:li resource="https://blog.zhifouli.top/index.php/archives/22/"/>
</rdf:Seq>
</items>
</channel>
<item rdf:about="https://blog.zhifouli.top/index.php/archives/27/">
<title>Bearsimple V2侧边栏分类统计计数异常修复</title>
<link>https://blog.zhifouli.top/index.php/archives/27/</link>
<dc:date>2025-07-25T10:42:00+08:00</dc:date>
<description>                                                            AI摘要       Bearsimple V2主题修复了侧边栏分类计数异常问题，通过添加代码正确计算一级分类及其子分类的文章总数，使显示结果更准确。         此内容根据文章生成，仅用于文章内容的解释与总结 Typecho主题 - Bearsimple V2侧边栏的根分类计数为0，没有正确计算和现实分类树的权值总和在sidebar.php加上统计的逻辑代码&lt;?php 
// 修复一级分类文章数显示问题：计算一级分类及其子分类的文章总数
// 原始代码只显示一级分类本身的文章数，不包括子分类的文章数
$totalCount = $categorys-&gt;count; // 一级分类本身的文章数
if (!empty($children)) {
    // 遍历所有子分类，累加它们的文章数
    foreach ($children as $mid) {
        $child = $categorys-&gt;getCategory($mid);
        $totalCount += $child[&#039;count&#039;]; // 累加子分类文章数
    }
}
?&gt;
&lt;?php if (empty($children)) { ?&gt;
    &lt;li&gt;
      &lt;div class=&quot;tree-node&quot;&gt;
        &lt;a href=&quot;&lt;?php $categorys-&gt;permalink(); ?&gt;&quot; class=&quot;category-link&quot;&gt;&lt;?php $categorys-&gt;name(); ?&gt; &lt;span class=&quot;category-count&quot;&gt;(&lt;?php echo $categorys-&gt;count(); ?&gt;)&lt;/span&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/li&gt;
   &lt;?php } else { ?&gt;
  &lt;li&gt;
      &lt;div class=&quot;tree-node&quot;&gt;
        &lt;span class=&quot;toggle-icon&quot;&gt;&lt;/span&gt;
        &lt;!-- 对于有子分类的一级分类，显示包含子分类文章数的总计数 --&gt;
        &lt;a href=&quot;&lt;?php $categorys-&gt;permalink(); ?&gt;&quot; class=&quot;category-link&quot;&gt;&lt;?php $categorys-&gt;name(); ?&gt; &lt;span class=&quot;category-count&quot;&gt;(&lt;?php echo $totalCount; ?&gt;)&lt;/span&gt;&lt;/a&gt;
      &lt;/div&gt;
      &lt;ul class=&quot;tree-view&quot;&gt;
          &lt;?php foreach ($children as $mid) { ?&gt;成功显示</description>
</item>
<item rdf:about="https://blog.zhifouli.top/index.php/archives/22/">
<title>解决 AISummary插件自定义样式未遍历多容器导致内容不显示的问题</title>
<link>https://blog.zhifouli.top/index.php/archives/22/</link>
<dc:date>2025-07-25T01:00:00+08:00</dc:date>
<description>                                                            AI摘要       文章介绍了在使用AISummary插件时，因多容器导致摘要内容不显示的问题，并提供了遍历所有容器的增强代码及样式调整方案。         此内容根据文章生成，仅用于文章内容的解释与总结 引言在为博客文章实现AI摘要工具时，我选择了 大佬--旋的来AISummary插件增强功能（非常好用）。然而，在按大佬的教程配置完毕后，我发现摘要正文并没有输出，经研究后得知，因为阅读模式的存在，出现了两个摘要容器，而大佬的自定义样式不会处理多个摘要容器，导致第二个摘要容器正文无法正常显示（当时不知道(⊙︿⊙)）。本文将详细记录这一问题的排查与解决方案，并在文末给出增强后的完整自定义样式代码。插件文章链接：Typecho添加文章AI摘要功能（Handsome等全主题适配）By xuan问题描述使用环境博客平台: Typecho博客主题: bearsimple具体问题现象摘要正文未能正常加载排查过程分析文章页的HTML文档可以看到，同时存在两个摘要容器，分别位于阅读模式页面处和文章页面处，并且阅读模式的容器为1号位，且1号位容器内容正常加载，而2号位为空值。故产生的现象为文章处摘要不加载，而阅读模式不会自动被使用，本人对该主题也是刚接触使用，不甚熟悉，故对本人的排查造成了不小的困扰。分析源代码主要的逻辑在executeAiSummaryTyping()中，其只处理了第一个容器function executeAiSummaryTyping() {
    // 【未增强版本】
    // 使用 document.querySelector() 只会获取页面上第一个匹配 &#039;.ai-typewriter-text&#039; 的元素。
    // 这意味着如果页面上有多个AI摘要容器，只有第一个摘要会执行打字机效果。
    const typewriterElement = document.querySelector(&#039;.ai-typewriter-text&#039;);
    // 获取隐藏的源文本元素。
    const sourceTextElement = document.querySelector(&#039;.ai-hidden-text&#039;);
    // 定义打字速度。
    const typingSpeed = 50; 
    
    // 如果没有找到对应的元素，则直接返回。
    if (!typewriterElement || !sourceTextElement) return;
    
    // 【未增强版本】
    // 使用全局变量 aiSummaryTypingTimeoutId 来管理定时器。
    // 当页面上有多个摘要时，如果前一个摘要的打字机效果还在进行中，新的打字机效果可能会清除掉旧的定时器，
    // 导致效果异常或只显示一个摘要的打字机效果。
    if (aiSummaryTypingTimeoutId) {
        clearTimeout(aiSummaryTypingTimeoutId);
    }

    // 获取并处理源文本，添加首行缩进。
    let textToType = sourceTextElement.textContent.trim();
    
    if (textToType.length &gt; 0) {
        textToType = &#039;  &#039; + textToType; // 首行缩进
    }

    // 清空打字机文本内容。
    typewriterElement.textContent = &#039;&#039;;
    // 初始化字符索引。
    let charIndex = 0;

    // 定义打字机效果的内部函数。
    function typeNextCharacter() {
        // 如果还有字符未输出。
        if (charIndex &lt; textToType.length) {
            // 逐个添加字符。
            typewriterElement.textContent += textToType.charAt(charIndex);
            charIndex++;
            // 设置定时器，继续输出下一个字符。
            // 【未增强版本】这里仍然使用全局变量来存储定时器ID。
            aiSummaryTypingTimeoutId = setTimeout(typeNextCharacter, typingSpeed);
        } else {
            // 所有字符输出完毕，清除全局定时器ID。
            aiSummaryTypingTimeoutId = null;
        }
    }
    // 启动打字机效果。
    typeNextCharacter();
}解决方案对函数做多容器增强function executeAiSummaryTyping() {
    // 获取页面上所有带有 &#039;aisummary&#039; 类的元素，这些元素代表了不同的AI摘要容器。
    const aiSummaryContainers = document.querySelectorAll(&#039;.aisummary&#039;);

    // 遍历每一个找到的AI摘要容器。
    aiSummaryContainers.forEach(container =&gt; {
        // 在当前容器内部，查找带有 &#039;ai-typewriter-text&#039; 类的元素，这是显示打字机效果的文本区域。
        const typewriterElement = container.querySelector(&#039;.ai-typewriter-text&#039;);
        // 在当前容器内部，查找带有 &#039;ai-hidden-text&#039; 类的元素，这是存储原始摘要文本的隐藏区域。
        const sourceTextElement = container.querySelector(&#039;.ai-hidden-text&#039;);
        // 定义打字速度，数值越小，打字速度越快。
        const typingSpeed = 50; 

        // 如果在当前容器中没有找到打字机文本元素或源文本元素，则跳过当前容器，不执行打字机效果。
        if (!typewriterElement || !sourceTextElement) return;

        // 清除可能存在的旧定时器。
        // 这里将定时器ID存储在 &#039;typewriterElement&#039; 自身的属性 &#039;typingTimeoutId&#039; 上，
        // 这样每个打字机元素都有独立的定时器，避免相互干扰，支持多摘要同时运行。
        if (typewriterElement.typingTimeoutId) {
            clearTimeout(typewriterElement.typingTimeoutId);
        }

        // 获取源文本内容并去除首尾空格。
        let textToType = sourceTextElement.textContent.trim();
        
        // 如果源文本不为空，则在文本开头添加两个空格，实现首行缩进效果。
        if (textToType.length &gt; 0) {
            textToType = &#039;  &#039; + textToType; 
        }

        // 清空打字机文本元素的当前内容，准备开始打字。
        typewriterElement.textContent = &#039;&#039;;
        // 初始化字符索引，用于追踪当前打字到哪个字符。
        let charIndex = 0;

        // 定义核心的打字机效果函数。
        const typeNextCharacter = () =&gt; {
            // 如果还有未输出的字符。
            if (charIndex &lt; textToType.length) {
                // 将当前字符添加到打字机文本元素中。
                typewriterElement.textContent += textToType.charAt(charIndex);
                // 字符索引递增。
                charIndex++;
                // 设置一个定时器，在指定延迟后再次调用 &#039;typeNextCharacter&#039; 函数，实现逐字输出。
                typewriterElement.typingTimeoutId = setTimeout(typeNextCharacter, typingSpeed);
            } else {
                // 所有字符都已输出完毕，清除该打字机元素的定时器ID。
                typewriterElement.typingTimeoutId = null;
            }
        };
        // 启动打字机效果，开始输出第一个字符。
        typeNextCharacter();
    });
}并用伪元素实现字符缩进.ai-typewriter-text {
    display: inline;
    word-wrap: break-word;
    white-space: pre-wrap;
}

/* 缩进样式 */
.ai-typewriter-text::before {
    content: &#039;&#039;;
    width: 2em; /* 调整宽度以匹配所需的缩进 */
    height: 1em; /* 高度与字体大小相匹配 */
    float: left;
    margin-top: -0.5em; /* 调整这个值以对齐文本基线 */
}验证修复效果可以看到，两个容器都能正常加载数据，且缩进会更为合适文章链接：效果展示总结通过这次经历，我记住了在排查前端页面的渲染加载问题时，可以直接从HTML文档出发，从元素本身出发，这样方便我们由果溯因，从而少走弯路，节省时间和精力。再次感谢大佬，不但开发了如此好用的插件（有类似插件付费提供商），还会积极讨论解决问题，希望我的经验能够帮助到其他遇到类似问题的朋友。完整自定义样式&lt;!-- AI摘要样式 - 阅读模式多摘要容器增强版 --&gt;
&lt;style&gt;
/* 摘要容器样式 */
.aisummary {
    background: #f7f7f9;
    border-radius: 12px;
    padding: 12px;
    box-shadow: 0 8px 16px -4px rgba(44, 45, 48, 0.047);
    border: 1px solid #e3e8f7;
    margin: 25px 0 30px;
    color: #333;
    position: relative;
    overflow: hidden;
}

/* 标题样式 */
.ai-header {
    margin-bottom: 10px !important;
    color: #465CEB !important;
    text-align: left !important;
    display: flex !important;
    align-items: center !important;
    text-indent: 0 !important;
    font-weight: bold !important;
    font-size: 17px !important;
}

.ai-header svg {
    margin-right: 8px;
    width: 24px;
    height: 24px;
    stroke: currentColor;
}

/* 文本容器样式 */
.ai-text-container {
    background: #fff;
    border-radius: 8px;
    padding: 12px 15px;
    border: 1px solid #e3e8f7;
    margin-bottom: 10px;
    font-size: 15px;
    line-height: 1.7;
    color: #333;
}

.ai-hidden-text {
    display: none;
}

.ai-typewriter-text {
    display: inline;
    word-wrap: break-word;
    white-space: pre-wrap;
}

/* 缩进样式 */
.ai-typewriter-text::before {
    content: &#039;&#039;;
    width: 2em; /* 调整宽度以匹配所需的缩进 */
    height: 1em; /* 高度与字体大小相匹配 */
    float: left;
    margin-top: -0.5em; /* 调整这个值以对齐文本基线 */
}

/* 光标样式及动画 */
.ai-cursor {
    display: inline-block;
    width: 2px;
    height: 1em;
    background-color: #465CEB;
    margin-left: 3px;
    animation: ai-blink 0.7s infinite;
    vertical-align: middle;
}

@keyframes ai-blink {
    0%, 100% { opacity: 1; }
    50% { opacity: 0; }
}

/* 页脚样式 */
.ai-footer {
    font-size: 13px !important;
    color: rgba(60, 60, 67, 0.65) !important;
    font-style: italic !important;
    margin-bottom: 0 !important;
    padding: 0 5px !important;
    text-align: left !important;
    text-indent: 0 !important;
    margin-top: 10px !important;
}

/* 响应式调整 */
@media (max-width: 768px) {
    .aisummary {
        padding: 10px;
        margin: 20px 0 25px;
    }
    .ai-header {
        font-size: 16px !important;
    }
    .ai-header svg {
        width: 22px;
        height: 22px;
        margin-right: 6px;
    }
    .ai-text-container {
        font-size: 14px;
        padding: 10px 12px;
        line-height: 1.65;
    }
    .ai-footer {
        font-size: 12px !important;
        margin-top: 8px !important;
    }
}

/* 暗色模式适配 */
[data-night=&quot;night&quot;] .aisummary,
.dark-mode .aisummary,
body.dark .aisummary,
body.night .aisummary,
.night .aisummary,
.night-mode .aisummary,
html.night .aisummary,
.theme-dark .aisummary {
    background: #2c2c2e;
    border-color: #38383a;
    color: #d1d1d1;
    box-shadow: 0 8px 16px -4px rgba(0, 0, 0, 0.15);
}

[data-night=&quot;night&quot;] .ai-text-container,
.dark-mode .ai-text-container,
body.dark .ai-text-container,
body.night .ai-text-container,
.night .ai-text-container,
.night-mode .ai-text-container,
html.night .ai-text-container,
.theme-dark .ai-text-container {
    background: #333333;
    border-color: #4a4a4a;
    color: #c8c8c8;
}

[data-night=&quot;night&quot;] .ai-header,
.dark-mode .ai-header,
body.dark .ai-header,
body.night .ai-header,
.night .ai-header,
.night-mode .ai-header,
html.night .ai-header,
.theme-dark .ai-header {
    color: #7c89f1 !important;
}

[data-night=&quot;night&quot;] .ai-cursor,
.dark-mode .ai-cursor,
body.dark .ai-cursor,
body.night .ai-cursor,
.night .ai-cursor,
.night-mode .ai-cursor,
html.night .ai-cursor,
.theme-dark .ai-cursor {
    background-color: #7c89f1;
}

[data-night=&quot;night&quot;] .ai-footer,
.dark-mode .ai-footer,
body.dark .ai-footer,
body.night .ai-footer,
.night .ai-footer,
.night-mode .ai-footer,
html.night .ai-footer,
.theme-dark .ai-footer {
    color: rgba(200, 200, 200, 0.6) !important;
}

/* 手动添加的暗色模式类 */
.aisummary.ai-dark-theme {
    background: #2c2c2e;
    border-color: #38383a;
    color: #d1d1d1;
    box-shadow: 0 8px 16px -4px rgba(0, 0, 0, 0.15);
}

.ai-dark-theme .ai-text-container {
    background: #333333;
    border-color: #4a4a4a;
    color: #c8c8c8;
}

.ai-dark-theme .ai-header {
    color: #7c89f1 !important;
}

.ai-dark-theme .ai-cursor {
    background-color: #7c89f1;
}

.ai-dark-theme .ai-footer {
    color: rgba(200, 200, 200, 0.6) !important;
}
&lt;/style&gt;

&lt;!-- AI摘要打字机效果脚本 --&gt;
&lt;script&gt;
    // 全局变量
    let aiSummaryTypingTimeoutId = null;
    let aiSummaryLastProcessedUrl = window.location.href;
    
    // AI摘要主题设置函数
    window.aiSummaryUser = {
        setAiSummaryTheme: function(theme) {
            const summaryElements = document.querySelectorAll(&#039;.aisummary&#039;);
            if (summaryElements.length &gt; 0) {
                summaryElements.forEach(element =&gt; {
                    if (theme === &#039;dark&#039;) {
                        element.classList.add(&#039;ai-dark-theme&#039;);
                    } else {
                        element.classList.remove(&#039;ai-dark-theme&#039;);
                    }
                });
            }
        }
    };

    // 检测并同步Handsome主题的夜间模式
    function detectAndSyncTheme() {
        // 检查常见的夜间模式标识
        const isDarkMode = 
            document.body.classList.contains(&#039;night&#039;) || 
            document.body.classList.contains(&#039;dark&#039;) || 
            document.documentElement.classList.contains(&#039;night&#039;) ||
            document.documentElement.getAttribute(&#039;data-night&#039;) === &#039;night&#039; ||
            document.querySelector(&#039;html&#039;).classList.contains(&#039;dark-mode&#039;) ||
            document.querySelector(&#039;[data-theme=&quot;dark&quot;]&#039;) !== null;
            
        // 应用对应的主题
        if (isDarkMode) {
            window.aiSummaryUser.setAiSummaryTheme(&#039;dark&#039;);
        } else {
            window.aiSummaryUser.setAiSummaryTheme(&#039;light&#039;);
        }
    }

    // 打字机效果核心逻辑
    function executeAiSummaryTyping() {
        // 获取所有AI摘要容器
        const aiSummaryContainers = document.querySelectorAll(&#039;.aisummary&#039;);

        // 遍历每个AI摘要容器
        aiSummaryContainers.forEach(container =&gt; {
            // 获取当前容器内的打字机文本元素和隐藏的源文本元素
            const typewriterElement = container.querySelector(&#039;.ai-typewriter-text&#039;);
            const sourceTextElement = container.querySelector(&#039;.ai-hidden-text&#039;);
            const typingSpeed = 50; // 打字速度，数值越小越快

            // 如果没有找到对应的元素，则跳过当前容器
            if (!typewriterElement || !sourceTextElement) return;

            // 清除可能存在的旧定时器，防止重复执行
            if (typewriterElement.typingTimeoutId) {
                clearTimeout(typewriterElement.typingTimeoutId);
            }

            // 获取并处理源文本，添加首行缩进
            let textToType = sourceTextElement.textContent.trim();
            if (textToType.length &gt; 0) {
                textToType = &#039;  &#039; + textToType; // 首行缩进
            }

            // 初始化打字机文本内容和字符索引
            typewriterElement.textContent = &#039;&#039;;
            let charIndex = 0;

            // 定义打字机效果函数
            const typeNextCharacter = () =&gt; {
                // 如果还有字符未输出
                if (charIndex &lt; textToType.length) {
                    // 逐个添加字符到打字机文本元素
                    typewriterElement.textContent += textToType.charAt(charIndex);
                    charIndex++;
                    // 设置定时器，继续输出下一个字符
                    typewriterElement.typingTimeoutId = setTimeout(typeNextCharacter, typingSpeed);
                } else {
                    // 所有字符输出完毕，清除定时器ID
                    typewriterElement.typingTimeoutId = null;
                }
            };
            // 启动打字机效果
            typeNextCharacter();
        });
    }

    // 页面加载后执行
    document.addEventListener(&#039;DOMContentLoaded&#039;, function() {
        // 延迟执行，确保页面元素加载完毕
        setTimeout(() =&gt; {
            executeAiSummaryTyping(); // 执行打字机效果
            detectAndSyncTheme();     // 检测并同步主题
        }, 300);
    });

    // PJAX/SPA兼容处理
    setInterval(function() {
        if (window.location.href !== aiSummaryLastProcessedUrl) {
            aiSummaryLastProcessedUrl = window.location.href;
            // 延迟执行，确保新内容加载完毕
            setTimeout(() =&gt; {
                executeAiSummaryTyping(); // 重新执行打字机效果
                detectAndSyncTheme();     // 重新检测并同步主题
            }, 1000);
        }
    }, 100);
    
    // 监听主题切换
    const observer = new MutationObserver(function(mutations) {
        mutations.forEach(function(mutation) {
            if (mutation.attributeName === &#039;class&#039; || mutation.attributeName === &#039;data-night&#039;) {
                detectAndSyncTheme();
            }
        });
    });
    
    // 开始观察文档和body元素上的class变化
    document.addEventListener(&#039;DOMContentLoaded&#039;, function() {
        observer.observe(document.documentElement, { attributes: true });
        observer.observe(document.body, { attributes: true });
    });
    
    // 兼容Handsome主题的夜间模式切换事件
    document.addEventListener(&#039;DOMContentLoaded&#039;, function() {
        // 尝试找到夜间模式切换按钮并监听点击事件
        const nightModeButtons = document.querySelectorAll(&#039;[data-toggle-theme], .theme-toggle, #nightmode, .night-mode-btn&#039;);
        if (nightModeButtons.length &gt; 0) {
            nightModeButtons.forEach(button =&gt; {
                button.addEventListener(&#039;click&#039;, function() {
                    // 延迟检测，确保主题切换完成
                    setTimeout(detectAndSyncTheme, 100);
                });
            });
        }
    });

    // 如果存在全局主题切换函数，拦截它们以同步状态
    if (typeof window.switchNightMode === &#039;function&#039;) {
        const originalSwitchNightMode = window.switchNightMode;
        window.switchNightMode = function() {
            originalSwitchNightMode.apply(this, arguments);
            setTimeout(detectAndSyncTheme, 100);
        };
    }
&lt;/script&gt;</description>
</item>
</rdf:RDF>