逛知乎的时候,你有没有注意到右边那个不起眼的小目录?

它安安静静地贴着右侧,你往下翻,它跟着高亮当前章节。点击一下,页面平滑滚动过去。

这个交互看似简单,拆开来看,其实横跨了三个技术层:服务端模板(Liquid)布局(CSS)交互(JavaScript)

我这篇博客用的就是同样的方案,写一篇文章把它说清楚。


整体架构

┌─────────────────────────────────────────────┐
│  文章 header(标题、作者、时间、标签)         │
├────────────────────────────────────┬────────┤
│                                    │  📑 目录│
│   文章正文                          │        │
│                                    │  · 起步 │
│   ## 起步                          │  · 原理 │
│                                    │    · 第1步│
│   ### 第一步                       │    · 第2步│
│                                    │  · 总结 │
│                                    │        │
├────────────────────────────────────┴────────┤
│  相关笔记 / 页脚                            │
└─────────────────────────────────────────────┘

一共三步:

  1. Liquid 把文章的标题提取出来,生成纯目录 HTML
  2. CSS 把目录固定在右侧,做成「粘性侧边栏」
  3. JavaScript 监听滚动,自动高亮当前阅读的章节

每一步都不复杂,但组合起来效果很不错。


第一步:提取目录(Liquid)

Jekyll 是静态站点生成器,它在构建阶段就把 Markdown 转成了 HTML。这时候文章的 ##### 标题已经变成 <h2><h3> 标签了。

问题来了:我们需要在生成 HTML 之后、把 HTML 写入文件之前,把标题抓出来额外做成一份目录。

这就是 jekyll-toc 这个插件做的事。

jekyll-toc 做了什么

Jekyll 在渲染文章时,Liquid 变量 content 里存的是完整的文章 HTML。jekyll-toc 提供了两个 Liquid filter:

  • inject_anchors:扫描 content 里的 <h2><h6>,给每个标题加上 id 属性(如果还没有的话),方便锚点跳转。
  • toc_only:同样扫描标题,但只提取它们的层级结构,生成一个嵌套的 <ul> 列表。

用法很简单:


<nav>
  <div class="post-layout-dual">
  <div class="post-main">
    <article class="post h-entry" itemscope itemtype="http://schema.org/BlogPosting">

      <header class="post-header">
        <h1 class="post-title p-name" itemprop="headline">🌅 晨间新闻报告 | 2026年4月30日</h1>
        <p class="post-meta">
          <time class="dt-published" datetime="2026-04-30T15:00:00+00:00" itemprop="datePublished">Apr 30, 2026
          </time>• <span itemprop="author" itemscope itemtype="http://schema.org/Person"><span class="p-author h-card" itemprop="name">Way</span></span><span class="reading-time">• 阅读时间: 1 分钟</span>
        </p><div class="author-card">
  <div class="author-avatar">
    <img src="/My-Site/assets/icons/avatar-way.png" alt="Way" onerror="this.style.display='none'">
  </div>
  <div class="author-info">
    <div class="author-name">
      Way
      
        <span class="author-role">站长 · 开发者</span>
      
    </div>
    
    <div class="author-links">
      
        <a href="mailto:triplejno3@gmail.com" title="邮箱" class="author-link">📧</a>
      
      
        <a href="https://github.com/triplejno3-alt" target="_blank" rel="noopener" title="GitHub" class="author-link">🐙</a>
      
      
        <a href="https://moon2dream.qzz.io" target="_blank" rel="noopener" title="主页" class="author-link">🌐</a>
      
    </div>
  </div>
</div>

<style>
  .author-card {
    display: flex;
    align-items: center;
    gap: 1.2rem;
    margin: 2rem 0 1.5rem 0;
    padding: 1.2rem 1.5rem;
    background: var(--bg-card, #f8f9fa);
    border-radius: 12px;
    border: 1px solid var(--border-color, #eee);
    transition: box-shadow 0.2s;
  }
  .author-card:hover {
    box-shadow: 0 2px 12px rgba(0,0,0,0.08);
  }
  .author-avatar {
    flex-shrink: 0;
    width: 56px;
    height: 56px;
    border-radius: 50%;
    overflow: hidden;
    background: var(--primary, #2c3e50);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 1.5rem;
  }
  .author-avatar img {
    width: 100%;
    height: 100%;
    object-fit: cover;
  }
  .author-info {
    flex: 1;
    min-width: 0;
  }
  .author-name {
    font-weight: 600;
    font-size: 1.05rem;
    color: var(--primary, #2c3e50);
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.5rem;
  }
  .author-role {
    font-size: 0.8rem;
    font-weight: 400;
    color: var(--text-light, #888);
    background: var(--bg-tag, #eef0f2);
    padding: 2px 10px;
    border-radius: 12px;
  }
  .author-bio {
    margin: 0.3rem 0 0 0;
    font-size: 0.88rem;
    color: var(--text-light, #666);
    line-height: 1.4;
  }
  .author-links {
    margin-top: 0.3rem;
    display: flex;
    gap: 0.4rem;
  }
  .author-link {
    text-decoration: none;
    font-size: 0.85rem;
    opacity: 0.7;
    transition: opacity 0.2s;
  }
  .author-link:hover {
    opacity: 1;
  }

  @media (max-width: 480px) {
    .author-card {
      flex-direction: column;
      text-align: center;
      gap: 0.8rem;
    }
    .author-name {
      justify-content: center;
    }
    .author-links {
      justify-content: center;
    }
  }
</style>
</header>

      <div class="post-content e-content post-content-with-toc" itemprop="articleBody">
        <h1 id="-晨间新闻报告--2026年4月30日">🌅 晨间新闻报告 | 2026年4月30日</h1>

<hr />

<h2 id="-国内要闻">🇨🇳 国内要闻</h2>

<h3 id="习近平以更大力度更实举措加强基础研究">习近平:以更大力度更实举措加强基础研究</h3>

<p>中共中央总书记、国家主席、中央军委主席习近平30日上午在上海出席<strong>加强基础研究座谈会</strong>并发表重要讲话。他强调,基础研究是整个科学体系的源头,是所有技术问题的总机关。要以更大力度、更实举措加强基础研究,提升我国原始创新能力,进一步打牢科技强国建设根基。座谈会由中共中央政治局常委丁薛祥主持。</p>

<p>在”五一”国际劳动节到来之际,习近平向全国广大劳动群众致以节日祝贺和诚挚慰问。</p>

<p>同日,习近平签署第七十四号、第七十五号、第七十六号主席令。此外,《习近平谈治国理政》第五卷英文版中马读者会在马来西亚吉隆坡举行。</p>

<h3 id="十四届全国人大常委会第二十二次会议闭幕">十四届全国人大常委会第二十二次会议闭幕</h3>

<p>会议30日上午在北京人民大会堂闭幕,赵乐际委员长主持。会议表决通过了<strong>社会救助法</strong>、新修订的<strong>监狱法</strong>等多项法律案。全国人大常委会还举行了宪法宣誓仪式。</p>

<p>经本次会议决定:<strong>张柱被任命为农业农村部部长</strong>,<strong>张成中被任命为应急管理部部长</strong>。</p>

<h3 id="中央纪委通报易会满被开除党籍和公职">中央纪委通报:易会满被开除党籍和公职</h3>

<p>经中共中央批准,中央纪委国家监委对第二十届中央委员、十四届全国政协经济委员会原副主任<strong>易会满</strong>严重违纪违法问题进行了立案审查调查,决定给予其开除党籍和公职处分。</p>

<h3 id="经济数据4月制造业pmi达503">经济数据:4月制造业PMI达50.3%</h3>

<p>国家统计局、中国物流与采购联合会发布数据显示,4月份中国制造业采购经理指数为<strong>50.3%</strong>,继续位于扩张区间,制造业延续较好运行态势。</p>

<p>发改委同日透露,2026年第二批915亿元”两新”设备更新项目清单和资金安排已下达。今年已累计安排1851亿元,占全年2000亿元目标的92%。</p>

<h3 id="五一假期出行高峰来临">五一假期出行高峰来临</h3>

<p>明天是”五一”假期第一天,全国出行客流明显增加。<strong>全国铁路预计今日发送旅客1995万人次</strong>,同比增长约8.9%。京沪、京哈、京广等高铁干线安排开行夜间高铁,重点车站开启24小时通宵运营模式。</p>

<h3 id="其他国内动态">其他国内动态</h3>

<ul>
  <li>我国发布新一轮找矿突破行动成果</li>
  <li>2026年”最美职工”先进事迹发布</li>
  <li>“亮剑2026”海洋伏季休渔执法行动启动</li>
  <li>2026”世界市长对话·西安”活动举行</li>
  <li>第九届数字中国建设峰会在福州迎来公众开放日</li>
  <li>国家副主席韩正在北京会见澳大利亚外长黄英贤</li>
</ul>

<hr />

<h2 id="-国际要闻">🌍 国际要闻</h2>

<h3 id="美伊局势持续升级美军海上封锁油价飙涨超6">美伊局势持续升级:美军海上封锁,油价飙涨超6%</h3>

<p>美国总统特朗普29日表示,美方将继续对<strong>伊朗实施海上封锁</strong>,直至伊方同意达成能消除美方对伊核计划担忧的协议。伊朗议长卡利巴夫回应称,美国的海上封锁已将油价推高到每桶<strong>120美元以上</strong>,同时企图通过制造伊朗内部分裂迫使伊朗屈服,呼吁国民保持团结。</p>

<p>受此影响,<strong>国际油价29日大幅上涨超6%</strong>。媒体报道称,约2万名海员已被困霍尔木兹海峡两个月。美国民主党方面批评称,对伊动武使美国陷入泥潭。特朗普则在另一场合表示,俄乌冲突和伊朗战事”可能在同一时间表上结束”。</p>

<h3 id="以色列空袭黎巴嫩至少28人遇难">以色列空袭黎巴嫩,至少28人遇难</h3>

<p>尽管2026年以黎停火协议已达成,以色列仍于30日在黎巴嫩多地发动一系列空袭,造成<strong>至少28人死亡</strong>。中东局势依然高度紧张。</p>

<h3 id="全球新闻自由跌至25年最低">全球新闻自由跌至25年最低</h3>

<p>无国界记者组织(RSF)发布最新报告称,全球新闻自由已降至<strong>2002年指数创立以来的最低水平</strong>。超过一半的国家被归类为”严重条件”,生活在拥有强新闻自由国家的人口比例已降至不足1%。</p>

<h3 id="俄罗斯图阿普谢油港大火扑灭居民拍到油雨从天而降">俄罗斯:图阿普谢油港大火扑灭,居民拍到”油雨”从天而降</h3>

<p>俄罗斯克拉斯诺达尔边疆区图阿普谢市油港发生重大火灾,经过数日燃烧后官方宣布大火已被扑灭。然而当地居民在社交媒体上发布视频,画面显示<strong>油污如雨般从天而降</strong>,引发严重环境灾难担忧。该油港此前遭到乌克兰无人机袭击。</p>

<h3 id="俄外交部东京审判意义重大对日本军国主义罪行无诉讼时效">俄外交部:东京审判意义重大,对日本军国主义罪行无诉讼时效</h3>

<p>5月3日是远东国际军事法庭东京审判开庭80周年纪念日。俄罗斯外交部发言人表示,东京审判在法律和全人类层面都具有重要意义,对日本军国主义犯下的反人类罪行没有诉讼时效限制。韩国民众也于近日集会,谴责日本军国主义抬头。</p>

<h3 id="其他国际速览">其他国际速览</h3>

<ul>
  <li><strong>俄罗斯</strong>表示将继续在马里保持军事存在,协助马里政府打击极端主义</li>
  <li><strong>英国普利茅斯</strong>发现一枚未爆炸的二战德军SC250航空炸弹,超1000户家庭被疏散</li>
  <li><strong>威尼斯双年展</strong>国际评审团因意大利政府反对俄罗斯参展而集体辞职</li>
  <li><strong>欧元区</strong>4月经济景气指数大幅下滑</li>
  <li><strong>日本</strong>国债收益率创近30年新高</li>
  <li>美国众议院通过国土安全部拨款法案,结束了创纪录的政府部分停摆</li>
  <li>美国最高法院裁定推翻路易斯安那州国会选区地图,并削弱《民权法案》关键条款</li>
  <li>前FBI局长科米在被最新起诉后首次出庭</li>
  <li>英国国王查尔斯三世访问美国</li>
</ul>

<hr />

<h2 id="-一句话快讯">📊 一句话快讯</h2>

<ul>
  <li>中央网信办将发布《AI应用伦理安全指引1.0》,明确划定”不得诱导情感依赖”等红线</li>
  <li>特朗普在白宫接见阿尔忒弥斯二号宇航员团队</li>
  <li>阿联酋退出OPEC引发国际能源市场连锁反应</li>
  <li>全国铁路五一期间新增夜间高铁车票预售期为5至7天</li>
</ul>

<hr />

<p><em>本报告综合自新华社、央视新闻、人民网、Wikipedia Current Events、Democracy Now! 等国内外权威信源。</em></p>

<p><em>早安,这是今天的世界。</em></p>

        
  <span class="post-views">
      • <span id="stats-view-count">...</span> 次阅读
    </span>
  <script>
    window.addEventListener('load', function() {
        if (!window.goatcounter || !window.goatcounter.get_data) return;

        var path = window.goatcounter.get_data()['p'];
        var token = "1lf3lupfunccb7awges6d8v96pgprwubf38je1zgle0yw67w6c";
        var url = "https://way.goatcounter.com/api/v0/stats/hits";

        fetch(url, {
            headers: {
                'Authorization': 'Bearer ' + token,
                'Content-Type': 'application/json'
            }
        })
        .then(function(response) {
            if (response.ok) {
                return response.json();
            }
            return Promise.reject(new Error('Network response was not ok.'));
        })
        .then(function(data) {
            var count = "0";
            if (data && data.hits) {
                var pageStats = data.hits.find(function(hit) {
                    return hit.path === path;
                });
                if (pageStats) {
                    count = pageStats.count || "0";
                }
            }
            document.querySelector('#stats-view-count').innerText = count;
        })
        .catch(function(error) {
            console.error('Error fetching reading stats:', error);
            document.querySelector('#stats-view-count').innerText = "0";
        });
    });
  </script>


      </div><div class="post-tags">
        <span class="post-tags-label">🏷️ 标签:</span>
        
        <a href="/My-Site/?tag=%E6%96%B0%E9%97%BB%E7%83%AD%E7%82%B9" class="post-tag">新闻热点</a>
        
        <a href="/My-Site/?tag=%E6%97%A9%E6%8A%A5" class="post-tag">早报</a>
        
        <a href="/My-Site/?tag=%E5%9B%BD%E9%99%85" class="post-tag">国际</a>
        
        <a href="/My-Site/?tag=%E5%9B%BD%E5%86%85" class="post-tag">国内</a>
        
      </div><a class="u-url" href="/My-Site/news/daily/2026/04/30/morning-news.html" hidden></a>
    </article>

    <!-- ====== Disqus 评论区 ====== -->
    <div id="disqus_thread" class="post-comments"></div>
    <script>
        var disqus_config = function () {
            this.page.url = 'https://triplejno3-alt.github.io/My-Site/news/daily/2026/04/30/morning-news.html';
            this.page.identifier = '/My-Site/news/daily/2026/04/30/morning-news.html';
        };
        (function() {
            var d = document, s = d.createElement('script');
            s.src = 'https://https-moon2dream-qzz-io.disqus.com/embed.js';
            s.setAttribute('data-timestamp', +new Date());
            (d.head || d.body).appendChild(s);
        })();
    </script>
    <noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript>
    <!-- ====== End Disqus ====== -->

  </div>

  
  <aside class="post-toc-sidebar" id="tocSidebar">
    <div class="toc-sticky">
      <div class="toc-header">📑 目录</div>
      
      
      <nav class="toc-nav" id="tocNav">
        <h1 id="-晨间新闻报告--2026年4月30日">🌅 晨间新闻报告 | 2026年4月30日</h1>

<hr />

<h2 id="-国内要闻">🇨🇳 国内要闻</h2>

<h3 id="习近平以更大力度更实举措加强基础研究">习近平:以更大力度更实举措加强基础研究</h3>

<p>中共中央总书记、国家主席、中央军委主席习近平30日上午在上海出席<strong>加强基础研究座谈会</strong>并发表重要讲话。他强调,基础研究是整个科学体系的源头,是所有技术问题的总机关。要以更大力度、更实举措加强基础研究,提升我国原始创新能力,进一步打牢科技强国建设根基。座谈会由中共中央政治局常委丁薛祥主持。</p>

<p>在”五一”国际劳动节到来之际,习近平向全国广大劳动群众致以节日祝贺和诚挚慰问。</p>

<p>同日,习近平签署第七十四号、第七十五号、第七十六号主席令。此外,《习近平谈治国理政》第五卷英文版中马读者会在马来西亚吉隆坡举行。</p>

<h3 id="十四届全国人大常委会第二十二次会议闭幕">十四届全国人大常委会第二十二次会议闭幕</h3>

<p>会议30日上午在北京人民大会堂闭幕,赵乐际委员长主持。会议表决通过了<strong>社会救助法</strong>、新修订的<strong>监狱法</strong>等多项法律案。全国人大常委会还举行了宪法宣誓仪式。</p>

<p>经本次会议决定:<strong>张柱被任命为农业农村部部长</strong>,<strong>张成中被任命为应急管理部部长</strong>。</p>

<h3 id="中央纪委通报易会满被开除党籍和公职">中央纪委通报:易会满被开除党籍和公职</h3>

<p>经中共中央批准,中央纪委国家监委对第二十届中央委员、十四届全国政协经济委员会原副主任<strong>易会满</strong>严重违纪违法问题进行了立案审查调查,决定给予其开除党籍和公职处分。</p>

<h3 id="经济数据4月制造业pmi达503">经济数据:4月制造业PMI达50.3%</h3>

<p>国家统计局、中国物流与采购联合会发布数据显示,4月份中国制造业采购经理指数为<strong>50.3%</strong>,继续位于扩张区间,制造业延续较好运行态势。</p>

<p>发改委同日透露,2026年第二批915亿元”两新”设备更新项目清单和资金安排已下达。今年已累计安排1851亿元,占全年2000亿元目标的92%。</p>

<h3 id="五一假期出行高峰来临">五一假期出行高峰来临</h3>

<p>明天是”五一”假期第一天,全国出行客流明显增加。<strong>全国铁路预计今日发送旅客1995万人次</strong>,同比增长约8.9%。京沪、京哈、京广等高铁干线安排开行夜间高铁,重点车站开启24小时通宵运营模式。</p>

<h3 id="其他国内动态">其他国内动态</h3>

<ul>
  <li>我国发布新一轮找矿突破行动成果</li>
  <li>2026年”最美职工”先进事迹发布</li>
  <li>“亮剑2026”海洋伏季休渔执法行动启动</li>
  <li>2026”世界市长对话·西安”活动举行</li>
  <li>第九届数字中国建设峰会在福州迎来公众开放日</li>
  <li>国家副主席韩正在北京会见澳大利亚外长黄英贤</li>
</ul>

<hr />

<h2 id="-国际要闻">🌍 国际要闻</h2>

<h3 id="美伊局势持续升级美军海上封锁油价飙涨超6">美伊局势持续升级:美军海上封锁,油价飙涨超6%</h3>

<p>美国总统特朗普29日表示,美方将继续对<strong>伊朗实施海上封锁</strong>,直至伊方同意达成能消除美方对伊核计划担忧的协议。伊朗议长卡利巴夫回应称,美国的海上封锁已将油价推高到每桶<strong>120美元以上</strong>,同时企图通过制造伊朗内部分裂迫使伊朗屈服,呼吁国民保持团结。</p>

<p>受此影响,<strong>国际油价29日大幅上涨超6%</strong>。媒体报道称,约2万名海员已被困霍尔木兹海峡两个月。美国民主党方面批评称,对伊动武使美国陷入泥潭。特朗普则在另一场合表示,俄乌冲突和伊朗战事”可能在同一时间表上结束”。</p>

<h3 id="以色列空袭黎巴嫩至少28人遇难">以色列空袭黎巴嫩,至少28人遇难</h3>

<p>尽管2026年以黎停火协议已达成,以色列仍于30日在黎巴嫩多地发动一系列空袭,造成<strong>至少28人死亡</strong>。中东局势依然高度紧张。</p>

<h3 id="全球新闻自由跌至25年最低">全球新闻自由跌至25年最低</h3>

<p>无国界记者组织(RSF)发布最新报告称,全球新闻自由已降至<strong>2002年指数创立以来的最低水平</strong>。超过一半的国家被归类为”严重条件”,生活在拥有强新闻自由国家的人口比例已降至不足1%。</p>

<h3 id="俄罗斯图阿普谢油港大火扑灭居民拍到油雨从天而降">俄罗斯:图阿普谢油港大火扑灭,居民拍到”油雨”从天而降</h3>

<p>俄罗斯克拉斯诺达尔边疆区图阿普谢市油港发生重大火灾,经过数日燃烧后官方宣布大火已被扑灭。然而当地居民在社交媒体上发布视频,画面显示<strong>油污如雨般从天而降</strong>,引发严重环境灾难担忧。该油港此前遭到乌克兰无人机袭击。</p>

<h3 id="俄外交部东京审判意义重大对日本军国主义罪行无诉讼时效">俄外交部:东京审判意义重大,对日本军国主义罪行无诉讼时效</h3>

<p>5月3日是远东国际军事法庭东京审判开庭80周年纪念日。俄罗斯外交部发言人表示,东京审判在法律和全人类层面都具有重要意义,对日本军国主义犯下的反人类罪行没有诉讼时效限制。韩国民众也于近日集会,谴责日本军国主义抬头。</p>

<h3 id="其他国际速览">其他国际速览</h3>

<ul>
  <li><strong>俄罗斯</strong>表示将继续在马里保持军事存在,协助马里政府打击极端主义</li>
  <li><strong>英国普利茅斯</strong>发现一枚未爆炸的二战德军SC250航空炸弹,超1000户家庭被疏散</li>
  <li><strong>威尼斯双年展</strong>国际评审团因意大利政府反对俄罗斯参展而集体辞职</li>
  <li><strong>欧元区</strong>4月经济景气指数大幅下滑</li>
  <li><strong>日本</strong>国债收益率创近30年新高</li>
  <li>美国众议院通过国土安全部拨款法案,结束了创纪录的政府部分停摆</li>
  <li>美国最高法院裁定推翻路易斯安那州国会选区地图,并削弱《民权法案》关键条款</li>
  <li>前FBI局长科米在被最新起诉后首次出庭</li>
  <li>英国国王查尔斯三世访问美国</li>
</ul>

<hr />

<h2 id="-一句话快讯">📊 一句话快讯</h2>

<ul>
  <li>中央网信办将发布《AI应用伦理安全指引1.0》,明确划定”不得诱导情感依赖”等红线</li>
  <li>特朗普在白宫接见阿尔忒弥斯二号宇航员团队</li>
  <li>阿联酋退出OPEC引发国际能源市场连锁反应</li>
  <li>全国铁路五一期间新增夜间高铁车票预售期为5至7天</li>
</ul>

<hr />

<p><em>本报告综合自新华社、央视新闻、人民网、Wikipedia Current Events、Democracy Now! 等国内外权威信源。</em></p>

<p><em>早安,这是今天的世界。</em></p>

      </nav>
      
    </div>
  </aside>
  
</div>

<style>
  .post-layout-dual {
    display: flex;
    gap: 2rem;
    justify-content: center;
    position: relative;
  }

  .post-main {
    flex: 0 1 800px;
    min-width: 0;
  }

  .post-toc-sidebar {
    flex: 0 0 240px;
    min-width: 0;
    position: relative;
  }

  .toc-sticky {
    position: sticky;
    top: 2rem;
    max-height: calc(100vh - 4rem);
    overflow-y: auto;
    padding: 0 0 1rem 0;
  }

  .toc-header {
    font-weight: 700;
    font-size: 0.95rem;
    color: var(--primary, #2c3e50);
    margin-bottom: 0.75rem;
    padding-bottom: 0.5rem;
    border-bottom: 1px solid #e5e7eb;
  }

  .toc-nav {
    font-size: 0.85rem;
    line-height: 1.6;
  }

  .toc-nav ul {
    list-style: none;
    padding: 0;
    margin: 0;
  }

  .toc-nav ul ul {
    padding-left: 1rem;
    margin-top: 0.15rem;
    margin-bottom: 0.15rem;
  }

  .toc-nav li {
    margin: 0.15rem 0;
  }

  .toc-nav a {
    display: block;
    padding: 0.2rem 0;
    color: #6b7280;
    text-decoration: none;
    border-left: 2px solid transparent;
    padding-left: 0.75rem;
    transition: all 0.15s ease;
    border-radius: 0;
  }

  .toc-nav a:hover {
    color: var(--accent, #667eea);
    border-left-color: var(--accent, #667eea);
  }

  .toc-nav a.active {
    color: var(--accent, #667eea);
    font-weight: 600;
    border-left-color: var(--accent, #667eea);
  }

  @media (max-width: 1100px) {
    .post-toc-sidebar {
      display: none;
    }
  }

  .post-toc-sidebar:empty {
    display: none;
  }

  /* ====== 代码块(post layout) ====== */
  .e-content pre {
    position: relative;
    background: #1e1e2e !important;
    color: #cdd6f4 !important;
    border-radius: 8px;
    padding: 1rem 1.25rem !important;
    font-size: 0.85rem;
    line-height: 1.6;
    overflow-x: auto;
    border: 1px solid #313244;
  }

  .e-content pre code {
    background: none !important;
    color: inherit !important;
    padding: 0 !important;
    font-family: 'JetBrains Mono', 'Fira Code', 'Cascadia Code', 'SF Mono', Consolas, monospace;
    font-size: 0.85rem;
  }

  .pre-lang-label {
    position: absolute;
    top: 0.5rem;
    left: 0.75rem;
    font-size: 0.7rem;
    color: #6c7086;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    pointer-events: none;
    z-index: 1;
  }

  .pre-copy-btn {
    position: absolute;
    top: 0.4rem;
    right: 0.75rem;
    background: none;
    border: 1px solid transparent;
    color: #6c7086;
    font-size: 0.75rem;
    cursor: pointer;
    padding: 2px 8px;
    border-radius: 4px;
    opacity: 0;
    transition: all 0.15s ease;
    z-index: 2;
  }

  pre:hover .pre-copy-btn,
  .pre-copy-btn:focus-visible {
    opacity: 1;
  }

  .pre-copy-btn:hover {
    color: #cdd6f4;
    border-color: #45475a;
    background: #313244;
  }

  .pre-copy-btn.copied {
    color: #a6e3a1;
    border-color: #a6e3a1;
  }

  pre.collapsible-code {
    max-height: none;
    cursor: default;
  }

  .pre-code-fold-btn {
    display: block;
    width: 100%;
    padding: 6px 0;
    background: #181825;
    color: #6c7086;
    font-size: 0.8rem;
    text-align: center;
    cursor: pointer;
    border: 1px solid #313244;
    border-top: none;
    border-radius: 0 0 8px 8px;
    transition: color 0.2s, background 0.2s;
    font-family: inherit;
    margin-top: -1px;
  }

  .pre-code-fold-btn:hover {
    color: #cdd6f4;
    background: #1e1e2e;
  }

  .post-header {
    margin-bottom: 2rem;
    padding-bottom: 1rem;
    border-bottom: 1px solid var(--border-color);
  }
  .post-title {
    font-size: 2.5rem;
    color: var(--primary);
    margin-bottom: 0.5rem;
  }
  .post-meta {
    color: var(--text-light);
    font-size: 0.9rem;
  }
  .post-views {
    color: var(--accent);
    font-weight: 600;
  }

  .post-tags {
    margin-top: 2.5rem;
    padding-top: 1.5rem;
    border-top: 1px solid var(--border-color);
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.5rem;
  }

  .post-tags-label {
    font-size: 0.9rem;
    color: var(--text-light);
  }

  .post-tag {
    display: inline-block;
    background: var(--tag-bg, rgba(142,150,170,0.14));
    color: var(--tag-text, #3c3c43);
    padding: 2px 10px;
    border-radius: 4px;
    font-size: 0.75rem;
    font-weight: 500;
    text-decoration: none;
    transition: background 0.2s;
  }

  .post-tag:hover {
    background: rgba(142,150,170,0.28);
  }

  /* ====== 评论区 ====== */
  .post-comments {
    margin-top: 3rem;
    padding-top: 2rem;
    border-top: 1px solid var(--border-color);
  }

  @media (max-width: 768px) {
    .post-title {
      font-size: 1.6rem;
    }
    .post-meta {
      font-size: 0.8rem;
    }
  }

  @media (max-width: 480px) {
    .post-title {
      font-size: 1.3rem;
    }
  }
</style>

<script>
document.addEventListener('DOMContentLoaded', function() {
  var tocNav = document.getElementById('tocNav');
  if (!tocNav) return;

  var links = tocNav.querySelectorAll('a');
  if (links.length === 0) return;

  var headings = [];
  links.forEach(function(link) {
    var href = link.getAttribute('href');
    if (href && href.startsWith('#')) {
      var el = document.getElementById(href.substring(1));
      if (el) headings.push({ el: el, link: link });
    }
  });

  if (headings.length === 0) {
    links.forEach(function(link) {
      var href = link.getAttribute('href');
      if (href && href.startsWith('#')) {
        var decodedId = decodeURIComponent(href.substring(1));
        var el = document.getElementById(decodedId);
        if (el) headings.push({ el: el, link: link });
      }
    });
  }

  if (headings.length === 0) return;

  function updateActiveLink() {
    var scrollY = window.scrollY + 80;
    var current = null;
    for (var i = headings.length - 1; i >= 0; i--) {
      if (headings[i].el.offsetTop <= scrollY) {
        current = headings[i];
        break;
      }
    }
    if (!current && headings.length > 0) {
      current = headings[0];
    }
    links.forEach(function(l) { l.classList.remove('active'); });
    if (current) {
      current.link.classList.add('active');
    }
  }

  setTimeout(updateActiveLink, 100);
  window.addEventListener('scroll', updateActiveLink, { passive: true });
});

// ====== 代码块样式增强:折叠 + 语言标签 + Copy ======
document.addEventListener('DOMContentLoaded', function() {
  var threshold = 40;
  var codeBlocks = document.querySelectorAll('.e-content pre');

  codeBlocks.forEach(function(pre) {
    var code = pre.querySelector('code');
    if (!code) return;

    var style = window.getComputedStyle(pre);
    if (style.position === 'static') pre.style.position = 'relative';

    var lang = '';
    code.className.split(/\s+/).forEach(function(cls) {
      var m = cls.match(/^language-(.+)$/);
      if (m) lang = m[1];
    });

    if (lang) {
      var label = document.createElement('span');
      label.className = 'pre-lang-label';
      label.textContent = lang;
      pre.appendChild(label);
    }

    var btn = document.createElement('button');
    btn.className = 'pre-copy-btn';
    btn.textContent = 'Copy';
    pre.appendChild(btn);

    btn.addEventListener('click', function(e) {
      e.stopPropagation();
      var text = code.textContent || code.innerText;
      navigator.clipboard.writeText(text).then(function() {
        btn.textContent = 'Copied!';
        btn.classList.add('copied');
        setTimeout(function() {
          btn.textContent = 'Copy';
          btn.classList.remove('copied');
        }, 2000);
      }).catch(function() {
        btn.textContent = 'Fail';
      });
    });

    var lines = code.innerHTML.split('\n');
    var start = 0, end = lines.length - 1;
    while (start < lines.length && lines[start].trim() === '') start++;
    while (end > start && lines[end].trim() === '') end--;
    var codeLineCount = Math.max(0, end - start + 1);

    if (codeLineCount < threshold) return;

    pre.classList.add('collapsible-code');

    var foldBtn = document.createElement('button');
    foldBtn.className = 'pre-code-fold-btn';
    foldBtn.textContent = '▲ 收起代码';
    pre.parentNode.insertBefore(foldBtn, pre.nextSibling);

    var isFolded = false;

    foldBtn.addEventListener('click', function(e) {
      e.stopPropagation();
      isFolded = !isFolded;
      if (isFolded) {
        code.innerHTML = lines.slice(0, start + threshold).join('\n');
        foldBtn.textContent = '▼ 展开剩余 ' + (codeLineCount - threshold) + ' 行';
      } else {
        code.innerHTML = lines.join('\n');
        foldBtn.textContent = '▲ 收起代码';
      }
    });
  });
});
</script>

</nav>

生成出来的 HTML 长这样:

<ul id="toc" class="toc-list">
  <li class="toc-item toc-h2"><a href="#整体架构">整体架构</a></li>
  <li class="toc-item toc-h2"><a href="#第一步提取目录liquid">第一步:提取目录</a>
    <ul>
      <li class="toc-item toc-h3"><a href="#jekyll-toc-做了什么">jekyll-toc 做了什么</a></li>
    </ul>
  </li>
  ...
</ul>

这里 toc-h2toc-h3 是自动添加的 CSS 类名,告诉我们这是几级标题。

文章正文部分,用 inject_anchors 替换原始的 content

<div class="post-content">
  <div class="post-layout-dual">
  <div class="post-main">
    <article class="post h-entry" itemscope itemtype="http://schema.org/BlogPosting">

      <header class="post-header">
        <h1 class="post-title p-name" itemprop="headline">🌅 晨间新闻报告 | 2026年4月30日</h1>
        <p class="post-meta">
          <time class="dt-published" datetime="2026-04-30T15:00:00+00:00" itemprop="datePublished">Apr 30, 2026
          </time>• <span itemprop="author" itemscope itemtype="http://schema.org/Person"><span class="p-author h-card" itemprop="name">Way</span></span><span class="reading-time">• 阅读时间: 1 分钟</span>
        </p><div class="author-card">
  <div class="author-avatar">
    <img src="/My-Site/assets/icons/avatar-way.png" alt="Way" onerror="this.style.display='none'">
  </div>
  <div class="author-info">
    <div class="author-name">
      Way
      
        <span class="author-role">站长 · 开发者</span>
      
    </div>
    
    <div class="author-links">
      
        <a href="mailto:triplejno3@gmail.com" title="邮箱" class="author-link">📧</a>
      
      
        <a href="https://github.com/triplejno3-alt" target="_blank" rel="noopener" title="GitHub" class="author-link">🐙</a>
      
      
        <a href="https://moon2dream.qzz.io" target="_blank" rel="noopener" title="主页" class="author-link">🌐</a>
      
    </div>
  </div>
</div>

<style>
  .author-card {
    display: flex;
    align-items: center;
    gap: 1.2rem;
    margin: 2rem 0 1.5rem 0;
    padding: 1.2rem 1.5rem;
    background: var(--bg-card, #f8f9fa);
    border-radius: 12px;
    border: 1px solid var(--border-color, #eee);
    transition: box-shadow 0.2s;
  }
  .author-card:hover {
    box-shadow: 0 2px 12px rgba(0,0,0,0.08);
  }
  .author-avatar {
    flex-shrink: 0;
    width: 56px;
    height: 56px;
    border-radius: 50%;
    overflow: hidden;
    background: var(--primary, #2c3e50);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 1.5rem;
  }
  .author-avatar img {
    width: 100%;
    height: 100%;
    object-fit: cover;
  }
  .author-info {
    flex: 1;
    min-width: 0;
  }
  .author-name {
    font-weight: 600;
    font-size: 1.05rem;
    color: var(--primary, #2c3e50);
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.5rem;
  }
  .author-role {
    font-size: 0.8rem;
    font-weight: 400;
    color: var(--text-light, #888);
    background: var(--bg-tag, #eef0f2);
    padding: 2px 10px;
    border-radius: 12px;
  }
  .author-bio {
    margin: 0.3rem 0 0 0;
    font-size: 0.88rem;
    color: var(--text-light, #666);
    line-height: 1.4;
  }
  .author-links {
    margin-top: 0.3rem;
    display: flex;
    gap: 0.4rem;
  }
  .author-link {
    text-decoration: none;
    font-size: 0.85rem;
    opacity: 0.7;
    transition: opacity 0.2s;
  }
  .author-link:hover {
    opacity: 1;
  }

  @media (max-width: 480px) {
    .author-card {
      flex-direction: column;
      text-align: center;
      gap: 0.8rem;
    }
    .author-name {
      justify-content: center;
    }
    .author-links {
      justify-content: center;
    }
  }
</style>
</header>

      <div class="post-content e-content post-content-with-toc" itemprop="articleBody">
        <h1 id="-晨间新闻报告--2026年4月30日">🌅 晨间新闻报告 | 2026年4月30日</h1>

<hr />

<h2 id="-国内要闻">🇨🇳 国内要闻</h2>

<h3 id="习近平以更大力度更实举措加强基础研究">习近平:以更大力度更实举措加强基础研究</h3>

<p>中共中央总书记、国家主席、中央军委主席习近平30日上午在上海出席<strong>加强基础研究座谈会</strong>并发表重要讲话。他强调,基础研究是整个科学体系的源头,是所有技术问题的总机关。要以更大力度、更实举措加强基础研究,提升我国原始创新能力,进一步打牢科技强国建设根基。座谈会由中共中央政治局常委丁薛祥主持。</p>

<p>在”五一”国际劳动节到来之际,习近平向全国广大劳动群众致以节日祝贺和诚挚慰问。</p>

<p>同日,习近平签署第七十四号、第七十五号、第七十六号主席令。此外,《习近平谈治国理政》第五卷英文版中马读者会在马来西亚吉隆坡举行。</p>

<h3 id="十四届全国人大常委会第二十二次会议闭幕">十四届全国人大常委会第二十二次会议闭幕</h3>

<p>会议30日上午在北京人民大会堂闭幕,赵乐际委员长主持。会议表决通过了<strong>社会救助法</strong>、新修订的<strong>监狱法</strong>等多项法律案。全国人大常委会还举行了宪法宣誓仪式。</p>

<p>经本次会议决定:<strong>张柱被任命为农业农村部部长</strong>,<strong>张成中被任命为应急管理部部长</strong>。</p>

<h3 id="中央纪委通报易会满被开除党籍和公职">中央纪委通报:易会满被开除党籍和公职</h3>

<p>经中共中央批准,中央纪委国家监委对第二十届中央委员、十四届全国政协经济委员会原副主任<strong>易会满</strong>严重违纪违法问题进行了立案审查调查,决定给予其开除党籍和公职处分。</p>

<h3 id="经济数据4月制造业pmi达503">经济数据:4月制造业PMI达50.3%</h3>

<p>国家统计局、中国物流与采购联合会发布数据显示,4月份中国制造业采购经理指数为<strong>50.3%</strong>,继续位于扩张区间,制造业延续较好运行态势。</p>

<p>发改委同日透露,2026年第二批915亿元”两新”设备更新项目清单和资金安排已下达。今年已累计安排1851亿元,占全年2000亿元目标的92%。</p>

<h3 id="五一假期出行高峰来临">五一假期出行高峰来临</h3>

<p>明天是”五一”假期第一天,全国出行客流明显增加。<strong>全国铁路预计今日发送旅客1995万人次</strong>,同比增长约8.9%。京沪、京哈、京广等高铁干线安排开行夜间高铁,重点车站开启24小时通宵运营模式。</p>

<h3 id="其他国内动态">其他国内动态</h3>

<ul>
  <li>我国发布新一轮找矿突破行动成果</li>
  <li>2026年”最美职工”先进事迹发布</li>
  <li>“亮剑2026”海洋伏季休渔执法行动启动</li>
  <li>2026”世界市长对话·西安”活动举行</li>
  <li>第九届数字中国建设峰会在福州迎来公众开放日</li>
  <li>国家副主席韩正在北京会见澳大利亚外长黄英贤</li>
</ul>

<hr />

<h2 id="-国际要闻">🌍 国际要闻</h2>

<h3 id="美伊局势持续升级美军海上封锁油价飙涨超6">美伊局势持续升级:美军海上封锁,油价飙涨超6%</h3>

<p>美国总统特朗普29日表示,美方将继续对<strong>伊朗实施海上封锁</strong>,直至伊方同意达成能消除美方对伊核计划担忧的协议。伊朗议长卡利巴夫回应称,美国的海上封锁已将油价推高到每桶<strong>120美元以上</strong>,同时企图通过制造伊朗内部分裂迫使伊朗屈服,呼吁国民保持团结。</p>

<p>受此影响,<strong>国际油价29日大幅上涨超6%</strong>。媒体报道称,约2万名海员已被困霍尔木兹海峡两个月。美国民主党方面批评称,对伊动武使美国陷入泥潭。特朗普则在另一场合表示,俄乌冲突和伊朗战事”可能在同一时间表上结束”。</p>

<h3 id="以色列空袭黎巴嫩至少28人遇难">以色列空袭黎巴嫩,至少28人遇难</h3>

<p>尽管2026年以黎停火协议已达成,以色列仍于30日在黎巴嫩多地发动一系列空袭,造成<strong>至少28人死亡</strong>。中东局势依然高度紧张。</p>

<h3 id="全球新闻自由跌至25年最低">全球新闻自由跌至25年最低</h3>

<p>无国界记者组织(RSF)发布最新报告称,全球新闻自由已降至<strong>2002年指数创立以来的最低水平</strong>。超过一半的国家被归类为”严重条件”,生活在拥有强新闻自由国家的人口比例已降至不足1%。</p>

<h3 id="俄罗斯图阿普谢油港大火扑灭居民拍到油雨从天而降">俄罗斯:图阿普谢油港大火扑灭,居民拍到”油雨”从天而降</h3>

<p>俄罗斯克拉斯诺达尔边疆区图阿普谢市油港发生重大火灾,经过数日燃烧后官方宣布大火已被扑灭。然而当地居民在社交媒体上发布视频,画面显示<strong>油污如雨般从天而降</strong>,引发严重环境灾难担忧。该油港此前遭到乌克兰无人机袭击。</p>

<h3 id="俄外交部东京审判意义重大对日本军国主义罪行无诉讼时效">俄外交部:东京审判意义重大,对日本军国主义罪行无诉讼时效</h3>

<p>5月3日是远东国际军事法庭东京审判开庭80周年纪念日。俄罗斯外交部发言人表示,东京审判在法律和全人类层面都具有重要意义,对日本军国主义犯下的反人类罪行没有诉讼时效限制。韩国民众也于近日集会,谴责日本军国主义抬头。</p>

<h3 id="其他国际速览">其他国际速览</h3>

<ul>
  <li><strong>俄罗斯</strong>表示将继续在马里保持军事存在,协助马里政府打击极端主义</li>
  <li><strong>英国普利茅斯</strong>发现一枚未爆炸的二战德军SC250航空炸弹,超1000户家庭被疏散</li>
  <li><strong>威尼斯双年展</strong>国际评审团因意大利政府反对俄罗斯参展而集体辞职</li>
  <li><strong>欧元区</strong>4月经济景气指数大幅下滑</li>
  <li><strong>日本</strong>国债收益率创近30年新高</li>
  <li>美国众议院通过国土安全部拨款法案,结束了创纪录的政府部分停摆</li>
  <li>美国最高法院裁定推翻路易斯安那州国会选区地图,并削弱《民权法案》关键条款</li>
  <li>前FBI局长科米在被最新起诉后首次出庭</li>
  <li>英国国王查尔斯三世访问美国</li>
</ul>

<hr />

<h2 id="-一句话快讯">📊 一句话快讯</h2>

<ul>
  <li>中央网信办将发布《AI应用伦理安全指引1.0》,明确划定”不得诱导情感依赖”等红线</li>
  <li>特朗普在白宫接见阿尔忒弥斯二号宇航员团队</li>
  <li>阿联酋退出OPEC引发国际能源市场连锁反应</li>
  <li>全国铁路五一期间新增夜间高铁车票预售期为5至7天</li>
</ul>

<hr />

<p><em>本报告综合自新华社、央视新闻、人民网、Wikipedia Current Events、Democracy Now! 等国内外权威信源。</em></p>

<p><em>早安,这是今天的世界。</em></p>

        
  <span class="post-views">
      • <span id="stats-view-count">...</span> 次阅读
    </span>
  <script>
    window.addEventListener('load', function() {
        if (!window.goatcounter || !window.goatcounter.get_data) return;

        var path = window.goatcounter.get_data()['p'];
        var token = "1lf3lupfunccb7awges6d8v96pgprwubf38je1zgle0yw67w6c";
        var url = "https://way.goatcounter.com/api/v0/stats/hits";

        fetch(url, {
            headers: {
                'Authorization': 'Bearer ' + token,
                'Content-Type': 'application/json'
            }
        })
        .then(function(response) {
            if (response.ok) {
                return response.json();
            }
            return Promise.reject(new Error('Network response was not ok.'));
        })
        .then(function(data) {
            var count = "0";
            if (data && data.hits) {
                var pageStats = data.hits.find(function(hit) {
                    return hit.path === path;
                });
                if (pageStats) {
                    count = pageStats.count || "0";
                }
            }
            document.querySelector('#stats-view-count').innerText = count;
        })
        .catch(function(error) {
            console.error('Error fetching reading stats:', error);
            document.querySelector('#stats-view-count').innerText = "0";
        });
    });
  </script>


      </div><div class="post-tags">
        <span class="post-tags-label">🏷️ 标签:</span>
        
        <a href="/My-Site/?tag=%E6%96%B0%E9%97%BB%E7%83%AD%E7%82%B9" class="post-tag">新闻热点</a>
        
        <a href="/My-Site/?tag=%E6%97%A9%E6%8A%A5" class="post-tag">早报</a>
        
        <a href="/My-Site/?tag=%E5%9B%BD%E9%99%85" class="post-tag">国际</a>
        
        <a href="/My-Site/?tag=%E5%9B%BD%E5%86%85" class="post-tag">国内</a>
        
      </div><a class="u-url" href="/My-Site/news/daily/2026/04/30/morning-news.html" hidden></a>
    </article>

    <!-- ====== Disqus 评论区 ====== -->
    <div id="disqus_thread" class="post-comments"></div>
    <script>
        var disqus_config = function () {
            this.page.url = 'https://triplejno3-alt.github.io/My-Site/news/daily/2026/04/30/morning-news.html';
            this.page.identifier = '/My-Site/news/daily/2026/04/30/morning-news.html';
        };
        (function() {
            var d = document, s = d.createElement('script');
            s.src = 'https://https-moon2dream-qzz-io.disqus.com/embed.js';
            s.setAttribute('data-timestamp', +new Date());
            (d.head || d.body).appendChild(s);
        })();
    </script>
    <noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript>
    <!-- ====== End Disqus ====== -->

  </div>

  
  <aside class="post-toc-sidebar" id="tocSidebar">
    <div class="toc-sticky">
      <div class="toc-header">📑 目录</div>
      
      
      <nav class="toc-nav" id="tocNav">
        <h1 id="-晨间新闻报告--2026年4月30日">🌅 晨间新闻报告 | 2026年4月30日</h1>

<hr />

<h2 id="-国内要闻">🇨🇳 国内要闻</h2>

<h3 id="习近平以更大力度更实举措加强基础研究">习近平:以更大力度更实举措加强基础研究</h3>

<p>中共中央总书记、国家主席、中央军委主席习近平30日上午在上海出席<strong>加强基础研究座谈会</strong>并发表重要讲话。他强调,基础研究是整个科学体系的源头,是所有技术问题的总机关。要以更大力度、更实举措加强基础研究,提升我国原始创新能力,进一步打牢科技强国建设根基。座谈会由中共中央政治局常委丁薛祥主持。</p>

<p>在”五一”国际劳动节到来之际,习近平向全国广大劳动群众致以节日祝贺和诚挚慰问。</p>

<p>同日,习近平签署第七十四号、第七十五号、第七十六号主席令。此外,《习近平谈治国理政》第五卷英文版中马读者会在马来西亚吉隆坡举行。</p>

<h3 id="十四届全国人大常委会第二十二次会议闭幕">十四届全国人大常委会第二十二次会议闭幕</h3>

<p>会议30日上午在北京人民大会堂闭幕,赵乐际委员长主持。会议表决通过了<strong>社会救助法</strong>、新修订的<strong>监狱法</strong>等多项法律案。全国人大常委会还举行了宪法宣誓仪式。</p>

<p>经本次会议决定:<strong>张柱被任命为农业农村部部长</strong>,<strong>张成中被任命为应急管理部部长</strong>。</p>

<h3 id="中央纪委通报易会满被开除党籍和公职">中央纪委通报:易会满被开除党籍和公职</h3>

<p>经中共中央批准,中央纪委国家监委对第二十届中央委员、十四届全国政协经济委员会原副主任<strong>易会满</strong>严重违纪违法问题进行了立案审查调查,决定给予其开除党籍和公职处分。</p>

<h3 id="经济数据4月制造业pmi达503">经济数据:4月制造业PMI达50.3%</h3>

<p>国家统计局、中国物流与采购联合会发布数据显示,4月份中国制造业采购经理指数为<strong>50.3%</strong>,继续位于扩张区间,制造业延续较好运行态势。</p>

<p>发改委同日透露,2026年第二批915亿元”两新”设备更新项目清单和资金安排已下达。今年已累计安排1851亿元,占全年2000亿元目标的92%。</p>

<h3 id="五一假期出行高峰来临">五一假期出行高峰来临</h3>

<p>明天是”五一”假期第一天,全国出行客流明显增加。<strong>全国铁路预计今日发送旅客1995万人次</strong>,同比增长约8.9%。京沪、京哈、京广等高铁干线安排开行夜间高铁,重点车站开启24小时通宵运营模式。</p>

<h3 id="其他国内动态">其他国内动态</h3>

<ul>
  <li>我国发布新一轮找矿突破行动成果</li>
  <li>2026年”最美职工”先进事迹发布</li>
  <li>“亮剑2026”海洋伏季休渔执法行动启动</li>
  <li>2026”世界市长对话·西安”活动举行</li>
  <li>第九届数字中国建设峰会在福州迎来公众开放日</li>
  <li>国家副主席韩正在北京会见澳大利亚外长黄英贤</li>
</ul>

<hr />

<h2 id="-国际要闻">🌍 国际要闻</h2>

<h3 id="美伊局势持续升级美军海上封锁油价飙涨超6">美伊局势持续升级:美军海上封锁,油价飙涨超6%</h3>

<p>美国总统特朗普29日表示,美方将继续对<strong>伊朗实施海上封锁</strong>,直至伊方同意达成能消除美方对伊核计划担忧的协议。伊朗议长卡利巴夫回应称,美国的海上封锁已将油价推高到每桶<strong>120美元以上</strong>,同时企图通过制造伊朗内部分裂迫使伊朗屈服,呼吁国民保持团结。</p>

<p>受此影响,<strong>国际油价29日大幅上涨超6%</strong>。媒体报道称,约2万名海员已被困霍尔木兹海峡两个月。美国民主党方面批评称,对伊动武使美国陷入泥潭。特朗普则在另一场合表示,俄乌冲突和伊朗战事”可能在同一时间表上结束”。</p>

<h3 id="以色列空袭黎巴嫩至少28人遇难">以色列空袭黎巴嫩,至少28人遇难</h3>

<p>尽管2026年以黎停火协议已达成,以色列仍于30日在黎巴嫩多地发动一系列空袭,造成<strong>至少28人死亡</strong>。中东局势依然高度紧张。</p>

<h3 id="全球新闻自由跌至25年最低">全球新闻自由跌至25年最低</h3>

<p>无国界记者组织(RSF)发布最新报告称,全球新闻自由已降至<strong>2002年指数创立以来的最低水平</strong>。超过一半的国家被归类为”严重条件”,生活在拥有强新闻自由国家的人口比例已降至不足1%。</p>

<h3 id="俄罗斯图阿普谢油港大火扑灭居民拍到油雨从天而降">俄罗斯:图阿普谢油港大火扑灭,居民拍到”油雨”从天而降</h3>

<p>俄罗斯克拉斯诺达尔边疆区图阿普谢市油港发生重大火灾,经过数日燃烧后官方宣布大火已被扑灭。然而当地居民在社交媒体上发布视频,画面显示<strong>油污如雨般从天而降</strong>,引发严重环境灾难担忧。该油港此前遭到乌克兰无人机袭击。</p>

<h3 id="俄外交部东京审判意义重大对日本军国主义罪行无诉讼时效">俄外交部:东京审判意义重大,对日本军国主义罪行无诉讼时效</h3>

<p>5月3日是远东国际军事法庭东京审判开庭80周年纪念日。俄罗斯外交部发言人表示,东京审判在法律和全人类层面都具有重要意义,对日本军国主义犯下的反人类罪行没有诉讼时效限制。韩国民众也于近日集会,谴责日本军国主义抬头。</p>

<h3 id="其他国际速览">其他国际速览</h3>

<ul>
  <li><strong>俄罗斯</strong>表示将继续在马里保持军事存在,协助马里政府打击极端主义</li>
  <li><strong>英国普利茅斯</strong>发现一枚未爆炸的二战德军SC250航空炸弹,超1000户家庭被疏散</li>
  <li><strong>威尼斯双年展</strong>国际评审团因意大利政府反对俄罗斯参展而集体辞职</li>
  <li><strong>欧元区</strong>4月经济景气指数大幅下滑</li>
  <li><strong>日本</strong>国债收益率创近30年新高</li>
  <li>美国众议院通过国土安全部拨款法案,结束了创纪录的政府部分停摆</li>
  <li>美国最高法院裁定推翻路易斯安那州国会选区地图,并削弱《民权法案》关键条款</li>
  <li>前FBI局长科米在被最新起诉后首次出庭</li>
  <li>英国国王查尔斯三世访问美国</li>
</ul>

<hr />

<h2 id="-一句话快讯">📊 一句话快讯</h2>

<ul>
  <li>中央网信办将发布《AI应用伦理安全指引1.0》,明确划定”不得诱导情感依赖”等红线</li>
  <li>特朗普在白宫接见阿尔忒弥斯二号宇航员团队</li>
  <li>阿联酋退出OPEC引发国际能源市场连锁反应</li>
  <li>全国铁路五一期间新增夜间高铁车票预售期为5至7天</li>
</ul>

<hr />

<p><em>本报告综合自新华社、央视新闻、人民网、Wikipedia Current Events、Democracy Now! 等国内外权威信源。</em></p>

<p><em>早安,这是今天的世界。</em></p>

      </nav>
      
    </div>
  </aside>
  
</div>

<style>
  .post-layout-dual {
    display: flex;
    gap: 2rem;
    justify-content: center;
    position: relative;
  }

  .post-main {
    flex: 0 1 800px;
    min-width: 0;
  }

  .post-toc-sidebar {
    flex: 0 0 240px;
    min-width: 0;
    position: relative;
  }

  .toc-sticky {
    position: sticky;
    top: 2rem;
    max-height: calc(100vh - 4rem);
    overflow-y: auto;
    padding: 0 0 1rem 0;
  }

  .toc-header {
    font-weight: 700;
    font-size: 0.95rem;
    color: var(--primary, #2c3e50);
    margin-bottom: 0.75rem;
    padding-bottom: 0.5rem;
    border-bottom: 1px solid #e5e7eb;
  }

  .toc-nav {
    font-size: 0.85rem;
    line-height: 1.6;
  }

  .toc-nav ul {
    list-style: none;
    padding: 0;
    margin: 0;
  }

  .toc-nav ul ul {
    padding-left: 1rem;
    margin-top: 0.15rem;
    margin-bottom: 0.15rem;
  }

  .toc-nav li {
    margin: 0.15rem 0;
  }

  .toc-nav a {
    display: block;
    padding: 0.2rem 0;
    color: #6b7280;
    text-decoration: none;
    border-left: 2px solid transparent;
    padding-left: 0.75rem;
    transition: all 0.15s ease;
    border-radius: 0;
  }

  .toc-nav a:hover {
    color: var(--accent, #667eea);
    border-left-color: var(--accent, #667eea);
  }

  .toc-nav a.active {
    color: var(--accent, #667eea);
    font-weight: 600;
    border-left-color: var(--accent, #667eea);
  }

  @media (max-width: 1100px) {
    .post-toc-sidebar {
      display: none;
    }
  }

  .post-toc-sidebar:empty {
    display: none;
  }

  /* ====== 代码块(post layout) ====== */
  .e-content pre {
    position: relative;
    background: #1e1e2e !important;
    color: #cdd6f4 !important;
    border-radius: 8px;
    padding: 1rem 1.25rem !important;
    font-size: 0.85rem;
    line-height: 1.6;
    overflow-x: auto;
    border: 1px solid #313244;
  }

  .e-content pre code {
    background: none !important;
    color: inherit !important;
    padding: 0 !important;
    font-family: 'JetBrains Mono', 'Fira Code', 'Cascadia Code', 'SF Mono', Consolas, monospace;
    font-size: 0.85rem;
  }

  .pre-lang-label {
    position: absolute;
    top: 0.5rem;
    left: 0.75rem;
    font-size: 0.7rem;
    color: #6c7086;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    pointer-events: none;
    z-index: 1;
  }

  .pre-copy-btn {
    position: absolute;
    top: 0.4rem;
    right: 0.75rem;
    background: none;
    border: 1px solid transparent;
    color: #6c7086;
    font-size: 0.75rem;
    cursor: pointer;
    padding: 2px 8px;
    border-radius: 4px;
    opacity: 0;
    transition: all 0.15s ease;
    z-index: 2;
  }

  pre:hover .pre-copy-btn,
  .pre-copy-btn:focus-visible {
    opacity: 1;
  }

  .pre-copy-btn:hover {
    color: #cdd6f4;
    border-color: #45475a;
    background: #313244;
  }

  .pre-copy-btn.copied {
    color: #a6e3a1;
    border-color: #a6e3a1;
  }

  pre.collapsible-code {
    max-height: none;
    cursor: default;
  }

  .pre-code-fold-btn {
    display: block;
    width: 100%;
    padding: 6px 0;
    background: #181825;
    color: #6c7086;
    font-size: 0.8rem;
    text-align: center;
    cursor: pointer;
    border: 1px solid #313244;
    border-top: none;
    border-radius: 0 0 8px 8px;
    transition: color 0.2s, background 0.2s;
    font-family: inherit;
    margin-top: -1px;
  }

  .pre-code-fold-btn:hover {
    color: #cdd6f4;
    background: #1e1e2e;
  }

  .post-header {
    margin-bottom: 2rem;
    padding-bottom: 1rem;
    border-bottom: 1px solid var(--border-color);
  }
  .post-title {
    font-size: 2.5rem;
    color: var(--primary);
    margin-bottom: 0.5rem;
  }
  .post-meta {
    color: var(--text-light);
    font-size: 0.9rem;
  }
  .post-views {
    color: var(--accent);
    font-weight: 600;
  }

  .post-tags {
    margin-top: 2.5rem;
    padding-top: 1.5rem;
    border-top: 1px solid var(--border-color);
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.5rem;
  }

  .post-tags-label {
    font-size: 0.9rem;
    color: var(--text-light);
  }

  .post-tag {
    display: inline-block;
    background: var(--tag-bg, rgba(142,150,170,0.14));
    color: var(--tag-text, #3c3c43);
    padding: 2px 10px;
    border-radius: 4px;
    font-size: 0.75rem;
    font-weight: 500;
    text-decoration: none;
    transition: background 0.2s;
  }

  .post-tag:hover {
    background: rgba(142,150,170,0.28);
  }

  /* ====== 评论区 ====== */
  .post-comments {
    margin-top: 3rem;
    padding-top: 2rem;
    border-top: 1px solid var(--border-color);
  }

  @media (max-width: 768px) {
    .post-title {
      font-size: 1.6rem;
    }
    .post-meta {
      font-size: 0.8rem;
    }
  }

  @media (max-width: 480px) {
    .post-title {
      font-size: 1.3rem;
    }
  }
</style>

<script>
document.addEventListener('DOMContentLoaded', function() {
  var tocNav = document.getElementById('tocNav');
  if (!tocNav) return;

  var links = tocNav.querySelectorAll('a');
  if (links.length === 0) return;

  var headings = [];
  links.forEach(function(link) {
    var href = link.getAttribute('href');
    if (href && href.startsWith('#')) {
      var el = document.getElementById(href.substring(1));
      if (el) headings.push({ el: el, link: link });
    }
  });

  if (headings.length === 0) {
    links.forEach(function(link) {
      var href = link.getAttribute('href');
      if (href && href.startsWith('#')) {
        var decodedId = decodeURIComponent(href.substring(1));
        var el = document.getElementById(decodedId);
        if (el) headings.push({ el: el, link: link });
      }
    });
  }

  if (headings.length === 0) return;

  function updateActiveLink() {
    var scrollY = window.scrollY + 80;
    var current = null;
    for (var i = headings.length - 1; i >= 0; i--) {
      if (headings[i].el.offsetTop <= scrollY) {
        current = headings[i];
        break;
      }
    }
    if (!current && headings.length > 0) {
      current = headings[0];
    }
    links.forEach(function(l) { l.classList.remove('active'); });
    if (current) {
      current.link.classList.add('active');
    }
  }

  setTimeout(updateActiveLink, 100);
  window.addEventListener('scroll', updateActiveLink, { passive: true });
});

// ====== 代码块样式增强:折叠 + 语言标签 + Copy ======
document.addEventListener('DOMContentLoaded', function() {
  var threshold = 40;
  var codeBlocks = document.querySelectorAll('.e-content pre');

  codeBlocks.forEach(function(pre) {
    var code = pre.querySelector('code');
    if (!code) return;

    var style = window.getComputedStyle(pre);
    if (style.position === 'static') pre.style.position = 'relative';

    var lang = '';
    code.className.split(/\s+/).forEach(function(cls) {
      var m = cls.match(/^language-(.+)$/);
      if (m) lang = m[1];
    });

    if (lang) {
      var label = document.createElement('span');
      label.className = 'pre-lang-label';
      label.textContent = lang;
      pre.appendChild(label);
    }

    var btn = document.createElement('button');
    btn.className = 'pre-copy-btn';
    btn.textContent = 'Copy';
    pre.appendChild(btn);

    btn.addEventListener('click', function(e) {
      e.stopPropagation();
      var text = code.textContent || code.innerText;
      navigator.clipboard.writeText(text).then(function() {
        btn.textContent = 'Copied!';
        btn.classList.add('copied');
        setTimeout(function() {
          btn.textContent = 'Copy';
          btn.classList.remove('copied');
        }, 2000);
      }).catch(function() {
        btn.textContent = 'Fail';
      });
    });

    var lines = code.innerHTML.split('\n');
    var start = 0, end = lines.length - 1;
    while (start < lines.length && lines[start].trim() === '') start++;
    while (end > start && lines[end].trim() === '') end--;
    var codeLineCount = Math.max(0, end - start + 1);

    if (codeLineCount < threshold) return;

    pre.classList.add('collapsible-code');

    var foldBtn = document.createElement('button');
    foldBtn.className = 'pre-code-fold-btn';
    foldBtn.textContent = '▲ 收起代码';
    pre.parentNode.insertBefore(foldBtn, pre.nextSibling);

    var isFolded = false;

    foldBtn.addEventListener('click', function(e) {
      e.stopPropagation();
      isFolded = !isFolded;
      if (isFolded) {
        code.innerHTML = lines.slice(0, start + threshold).join('\n');
        foldBtn.textContent = '▼ 展开剩余 ' + (codeLineCount - threshold) + ' 行';
      } else {
        code.innerHTML = lines.join('\n');
        foldBtn.textContent = '▲ 收起代码';
      }
    });
  });
});
</script>

</div>

这样每个 <h2> 就有了一个稳定的 id,目录里的 <a href="#..."> 才能跳转过去。

配置项

_config.yml 里可以控制目录深度:

toc:
  min_level: 2      # 从 h2 开始
  max_level: 3      # 只到 h3,不要 h4/h5

如果某篇文章不想显示目录,frontmatter 里写 toc: false 就行。


第二步:粘性侧边栏(CSS)

目录 HTML 已经生成好了,接下来要把它放到右侧并固定住。

双栏布局

最外层用一个 Flexbox 容器:

.post-layout-dual {
  display: flex;
  gap: 2rem;
  justify-content: center;
}

左栏(正文)宽度固定 800px:

.post-main {
  flex: 0 1 800px;
}

右栏(目录)宽度固定 240px:

.post-toc-sidebar {
  flex: 0 0 240px;
}

粘性定位

关键在这里——position: sticky

.toc-sticky {
  position: sticky;
  top: 2rem;
  max-height: calc(100vh - 4rem);
  overflow-y: auto;
}

position: sticky 的行为很巧妙:

  • 当页面还没往下滚到目录位置时,目录随着页面正常流动
  • 一旦 top: 2rem 的条件被触发(即目录距视口顶部 <2rem),目录就固定在原地不动
  • 页面继续往下,目录始终保持距视口顶部 2rem 的位置

这样你在读文章底部时,目录仍然在右侧可视范围内,不会滚走。

max-height: calc(100vh - 4rem) 保证目录不会超出屏幕高度,太长的话用 overflow-y: auto 内部滚动。

目录项的样式

每一行目录项的左侧有一条 2px 的灰色竖线:

.toc-nav a {
  border-left: 2px solid transparent;
  padding-left: 0.75rem;
  color: #6b7280;
  transition: all 0.15s ease;
}

.toc-nav a:hover {
  color: #667eea;
  border-left-color: #667eea;
}

悬停时变紫,点击后高亮也是紫色。这个设计和知乎的竖线指示器异曲同工。

移动端适配

小屏没有空间放侧边栏,直接隐藏:

@media (max-width: 1100px) {
  .post-toc-sidebar {
    display: none;
  }
}

宽度小于 1100px 时目录消失,文章回归单栏阅读,不受干扰。


第三步:滚动高亮(JavaScript)

硬骨头在这里——滚动时自动高亮当前章节。

原理

我们要做的是:

  1. 收集目录中所有链接对应的页面标题元素(<h2><h3>
  2. 监听 scroll 事件
  3. 每次滚动时,判断当前视口位置对应哪个标题
  4. 给对应的目录项加上 active

就这么简单。但细节里有几个坑。

匹配标题元素

从目录链接的 href 里提取 #id,然后用 document.getElementById() 找到页面里的标题元素:

var headings = [];

links.forEach(function(link) {
  var href = link.getAttribute('href');
  if (href && href.startsWith('#')) {
    var el = document.getElementById(href.substring(1));
    if (el) headings.push({ el: el, link: link });
  }
});

中文 URL 编码是个坑。#什么是-Everything 在页面里实际是 id="什么是-Everything"(Jekyll 生成了中文 ID),但链接的 href 值里中文可能被编码了。所以需要降级策略:

// 第一次匹配失败时,用 decodeURI 再试一次
if (headings.length === 0) {
  links.forEach(function(link) {
    var href = link.getAttribute('href');
    if (href && href.startsWith('#')) {
      var decodedId = decodeURIComponent(href.substring(1));
      var el = document.getElementById(decodedId);
      if (el) headings.push({ el: el, link: link });
    }
  });
}

判断当前章节

有了标题元素列表,怎么知道用户正在读哪个?

最简单的办法——从后往前遍历,找到第一个 offsetTop 小于当前滚动位置的标题:

function updateActiveLink() {
  var scrollY = window.scrollY + 80;  // +80 偏移让高亮提前一点

  var current = null;
  for (var i = headings.length - 1; i >= 0; i--) {
    if (headings[i].el.offsetTop <= scrollY) {
      current = headings[i];
      break;
    }
  }

  // 还没滚到任何标题时,默认高亮第一个
  if (!current && headings.length > 0) {
    current = headings[0];
  }

  // 移除所有 active,给当前加上
  links.forEach(function(l) { l.classList.remove('active'); });
  if (current) {
    current.link.classList.add('active');
  }
}

这里的 +80 是个「手感参数」——加上一个小偏移,让高亮比实际到达标题位置稍微提前一点点,体验更自然。

滚动事件绑定用 { passive: true } 告诉浏览器不需要阻止默认行为,浏览器可以优化滚动性能:

window.addEventListener('scroll', updateActiveLink, { passive: true });

为什么不建议用 Intersection Observer

很多文章会说「用 Intersection Observer 代替 scroll 事件」。但这里有一个尴尬的点:

Intersection Observer 监听的是元素是否进入视口。但一篇文章的标题通常只有 <h2> 加一点 padding,当它进入视口底部时用户还没读到那里。等它进入视口顶部时,又已经开始看下一节了

用 scroll + offsetTop 来做,反而更容易控制「手感」——加个偏移量,在用户刚进入新章节时就切换高亮,体验更顺滑。


从实现到阅读体验的闭环

现在我们回头看整个流程:

用户写 Markdown(## 标题)
      ↓
Jekyll 构建(Liquid + jekyll-toc)
  → inject_anchors 给标题加 id
  → toc_only 生成目录 HTML
      ↓
CSS sticky 定位(右侧侧边栏)
      ↓
JS scroll 监听(高亮当前章节)
      ↓
用户滚动阅读时自动跟踪位置

每一步都简单,但连起来就是一个不少人在用的、觉得「挺舒服」的功能。


完整的 Liquid 代码

这两个 layout 文件的完整实现:

---
layout: default
---
<div class="post-layout-dual">
  <div class="post-main">
    <article><!-- 文章正文 --></article>
  </div>

  
  <aside class="post-toc-sidebar">
    <div class="toc-sticky">
      <div class="toc-header">📑 目录</div>
      
      
      <nav class="toc-nav" id="tocNav">
        <div class="post-layout-dual">
  <div class="post-main">
    <article class="post h-entry" itemscope itemtype="http://schema.org/BlogPosting">

      <header class="post-header">
        <h1 class="post-title p-name" itemprop="headline">🌅 晨间新闻报告 | 2026年4月30日</h1>
        <p class="post-meta">
          <time class="dt-published" datetime="2026-04-30T15:00:00+00:00" itemprop="datePublished">Apr 30, 2026
          </time><span itemprop="author" itemscope itemtype="http://schema.org/Person"><span class="p-author h-card" itemprop="name">Way</span></span><span class="reading-time">• 阅读时间: 1 分钟</span>
        </p><div class="author-card">
  <div class="author-avatar">
    <img src="/My-Site/assets/icons/avatar-way.png" alt="Way" onerror="this.style.display='none'">
  </div>
  <div class="author-info">
    <div class="author-name">
      Way
      
        <span class="author-role">站长 · 开发者</span>
      
    </div>
    
    <div class="author-links">
      
        <a href="mailto:triplejno3@gmail.com" title="邮箱" class="author-link">📧</a>
      
      
        <a href="https://github.com/triplejno3-alt" target="_blank" rel="noopener" title="GitHub" class="author-link">🐙</a>
      
      
        <a href="https://moon2dream.qzz.io" target="_blank" rel="noopener" title="主页" class="author-link">🌐</a>
      
    </div>
  </div>
</div>

<style>
  .author-card {
    display: flex;
    align-items: center;
    gap: 1.2rem;
    margin: 2rem 0 1.5rem 0;
    padding: 1.2rem 1.5rem;
    background: var(--bg-card, #f8f9fa);
    border-radius: 12px;
    border: 1px solid var(--border-color, #eee);
    transition: box-shadow 0.2s;
  }
  .author-card:hover {
    box-shadow: 0 2px 12px rgba(0,0,0,0.08);
  }
  .author-avatar {
    flex-shrink: 0;
    width: 56px;
    height: 56px;
    border-radius: 50%;
    overflow: hidden;
    background: var(--primary, #2c3e50);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 1.5rem;
  }
  .author-avatar img {
    width: 100%;
    height: 100%;
    object-fit: cover;
  }
  .author-info {
    flex: 1;
    min-width: 0;
  }
  .author-name {
    font-weight: 600;
    font-size: 1.05rem;
    color: var(--primary, #2c3e50);
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.5rem;
  }
  .author-role {
    font-size: 0.8rem;
    font-weight: 400;
    color: var(--text-light, #888);
    background: var(--bg-tag, #eef0f2);
    padding: 2px 10px;
    border-radius: 12px;
  }
  .author-bio {
    margin: 0.3rem 0 0 0;
    font-size: 0.88rem;
    color: var(--text-light, #666);
    line-height: 1.4;
  }
  .author-links {
    margin-top: 0.3rem;
    display: flex;
    gap: 0.4rem;
  }
  .author-link {
    text-decoration: none;
    font-size: 0.85rem;
    opacity: 0.7;
    transition: opacity 0.2s;
  }
  .author-link:hover {
    opacity: 1;
  }

  @media (max-width: 480px) {
    .author-card {
      flex-direction: column;
      text-align: center;
      gap: 0.8rem;
    }
    .author-name {
      justify-content: center;
    }
    .author-links {
      justify-content: center;
    }
  }
</style>
</header>

      <div class="post-content e-content post-content-with-toc" itemprop="articleBody">
        <h1 id="-晨间新闻报告--2026年4月30日">🌅 晨间新闻报告 | 2026年4月30日</h1>

<hr />

<h2 id="-国内要闻">🇨🇳 国内要闻</h2>

<h3 id="习近平以更大力度更实举措加强基础研究">习近平:以更大力度更实举措加强基础研究</h3>

<p>中共中央总书记、国家主席、中央军委主席习近平30日上午在上海出席<strong>加强基础研究座谈会</strong>并发表重要讲话。他强调,基础研究是整个科学体系的源头,是所有技术问题的总机关。要以更大力度、更实举措加强基础研究,提升我国原始创新能力,进一步打牢科技强国建设根基。座谈会由中共中央政治局常委丁薛祥主持。</p>

<p>在”五一”国际劳动节到来之际,习近平向全国广大劳动群众致以节日祝贺和诚挚慰问。</p>

<p>同日,习近平签署第七十四号、第七十五号、第七十六号主席令。此外,《习近平谈治国理政》第五卷英文版中马读者会在马来西亚吉隆坡举行。</p>

<h3 id="十四届全国人大常委会第二十二次会议闭幕">十四届全国人大常委会第二十二次会议闭幕</h3>

<p>会议30日上午在北京人民大会堂闭幕,赵乐际委员长主持。会议表决通过了<strong>社会救助法</strong>、新修订的<strong>监狱法</strong>等多项法律案。全国人大常委会还举行了宪法宣誓仪式。</p>

<p>经本次会议决定:<strong>张柱被任命为农业农村部部长</strong><strong>张成中被任命为应急管理部部长</strong></p>

<h3 id="中央纪委通报易会满被开除党籍和公职">中央纪委通报:易会满被开除党籍和公职</h3>

<p>经中共中央批准,中央纪委国家监委对第二十届中央委员、十四届全国政协经济委员会原副主任<strong>易会满</strong>严重违纪违法问题进行了立案审查调查,决定给予其开除党籍和公职处分。</p>

<h3 id="经济数据4月制造业pmi达503">经济数据:4月制造业PMI达50.3%</h3>

<p>国家统计局、中国物流与采购联合会发布数据显示,4月份中国制造业采购经理指数为<strong>50.3%</strong>,继续位于扩张区间,制造业延续较好运行态势。</p>

<p>发改委同日透露,2026年第二批915亿元”两新”设备更新项目清单和资金安排已下达。今年已累计安排1851亿元,占全年2000亿元目标的92%。</p>

<h3 id="五一假期出行高峰来临">五一假期出行高峰来临</h3>

<p>明天是”五一”假期第一天,全国出行客流明显增加。<strong>全国铁路预计今日发送旅客1995万人次</strong>,同比增长约8.9%。京沪、京哈、京广等高铁干线安排开行夜间高铁,重点车站开启24小时通宵运营模式。</p>

<h3 id="其他国内动态">其他国内动态</h3>

<ul>
  <li>我国发布新一轮找矿突破行动成果</li>
  <li>2026年”最美职工”先进事迹发布</li>
  <li>“亮剑2026”海洋伏季休渔执法行动启动</li>
  <li>2026”世界市长对话·西安”活动举行</li>
  <li>第九届数字中国建设峰会在福州迎来公众开放日</li>
  <li>国家副主席韩正在北京会见澳大利亚外长黄英贤</li>
</ul>

<hr />

<h2 id="-国际要闻">🌍 国际要闻</h2>

<h3 id="美伊局势持续升级美军海上封锁油价飙涨超6">美伊局势持续升级:美军海上封锁,油价飙涨超6%</h3>

<p>美国总统特朗普29日表示,美方将继续对<strong>伊朗实施海上封锁</strong>,直至伊方同意达成能消除美方对伊核计划担忧的协议。伊朗议长卡利巴夫回应称,美国的海上封锁已将油价推高到每桶<strong>120美元以上</strong>,同时企图通过制造伊朗内部分裂迫使伊朗屈服,呼吁国民保持团结。</p>

<p>受此影响,<strong>国际油价29日大幅上涨超6%</strong>。媒体报道称,约2万名海员已被困霍尔木兹海峡两个月。美国民主党方面批评称,对伊动武使美国陷入泥潭。特朗普则在另一场合表示,俄乌冲突和伊朗战事”可能在同一时间表上结束”。</p>

<h3 id="以色列空袭黎巴嫩至少28人遇难">以色列空袭黎巴嫩,至少28人遇难</h3>

<p>尽管2026年以黎停火协议已达成,以色列仍于30日在黎巴嫩多地发动一系列空袭,造成<strong>至少28人死亡</strong>。中东局势依然高度紧张。</p>

<h3 id="全球新闻自由跌至25年最低">全球新闻自由跌至25年最低</h3>

<p>无国界记者组织(RSF)发布最新报告称,全球新闻自由已降至<strong>2002年指数创立以来的最低水平</strong>。超过一半的国家被归类为”严重条件”,生活在拥有强新闻自由国家的人口比例已降至不足1%。</p>

<h3 id="俄罗斯图阿普谢油港大火扑灭居民拍到油雨从天而降">俄罗斯:图阿普谢油港大火扑灭,居民拍到”油雨”从天而降</h3>

<p>俄罗斯克拉斯诺达尔边疆区图阿普谢市油港发生重大火灾,经过数日燃烧后官方宣布大火已被扑灭。然而当地居民在社交媒体上发布视频,画面显示<strong>油污如雨般从天而降</strong>,引发严重环境灾难担忧。该油港此前遭到乌克兰无人机袭击。</p>

<h3 id="俄外交部东京审判意义重大对日本军国主义罪行无诉讼时效">俄外交部:东京审判意义重大,对日本军国主义罪行无诉讼时效</h3>

<p>5月3日是远东国际军事法庭东京审判开庭80周年纪念日。俄罗斯外交部发言人表示,东京审判在法律和全人类层面都具有重要意义,对日本军国主义犯下的反人类罪行没有诉讼时效限制。韩国民众也于近日集会,谴责日本军国主义抬头。</p>

<h3 id="其他国际速览">其他国际速览</h3>

<ul>
  <li><strong>俄罗斯</strong>表示将继续在马里保持军事存在,协助马里政府打击极端主义</li>
  <li><strong>英国普利茅斯</strong>发现一枚未爆炸的二战德军SC250航空炸弹,超1000户家庭被疏散</li>
  <li><strong>威尼斯双年展</strong>国际评审团因意大利政府反对俄罗斯参展而集体辞职</li>
  <li><strong>欧元区</strong>4月经济景气指数大幅下滑</li>
  <li><strong>日本</strong>国债收益率创近30年新高</li>
  <li>美国众议院通过国土安全部拨款法案,结束了创纪录的政府部分停摆</li>
  <li>美国最高法院裁定推翻路易斯安那州国会选区地图,并削弱《民权法案》关键条款</li>
  <li>前FBI局长科米在被最新起诉后首次出庭</li>
  <li>英国国王查尔斯三世访问美国</li>
</ul>

<hr />

<h2 id="-一句话快讯">📊 一句话快讯</h2>

<ul>
  <li>中央网信办将发布《AI应用伦理安全指引1.0》,明确划定”不得诱导情感依赖”等红线</li>
  <li>特朗普在白宫接见阿尔忒弥斯二号宇航员团队</li>
  <li>阿联酋退出OPEC引发国际能源市场连锁反应</li>
  <li>全国铁路五一期间新增夜间高铁车票预售期为5至7天</li>
</ul>

<hr />

<p><em>本报告综合自新华社、央视新闻、人民网、Wikipedia Current Events、Democracy Now! 等国内外权威信源。</em></p>

<p><em>早安,这是今天的世界。</em></p>

        
  <span class="post-views"><span id="stats-view-count">...</span> 次阅读
    </span>
  <script>
    window.addEventListener('load', function() {
        if (!window.goatcounter || !window.goatcounter.get_data) return;

        var path = window.goatcounter.get_data()['p'];
        var token = "1lf3lupfunccb7awges6d8v96pgprwubf38je1zgle0yw67w6c";
        var url = "https://way.goatcounter.com/api/v0/stats/hits";

        fetch(url, {
            headers: {
                'Authorization': 'Bearer ' + token,
                'Content-Type': 'application/json'
            }
        })
        .then(function(response) {
            if (response.ok) {
                return response.json();
            }
            return Promise.reject(new Error('Network response was not ok.'));
        })
        .then(function(data) {
            var count = "0";
            if (data && data.hits) {
                var pageStats = data.hits.find(function(hit) {
                    return hit.path === path;
                });
                if (pageStats) {
                    count = pageStats.count || "0";
                }
            }
            document.querySelector('#stats-view-count').innerText = count;
        })
        .catch(function(error) {
            console.error('Error fetching reading stats:', error);
            document.querySelector('#stats-view-count').innerText = "0";
        });
    });
  </script>


      </div><div class="post-tags">
        <span class="post-tags-label">🏷️ 标签:</span>
        
        <a href="/My-Site/?tag=%E6%96%B0%E9%97%BB%E7%83%AD%E7%82%B9" class="post-tag">新闻热点</a>
        
        <a href="/My-Site/?tag=%E6%97%A9%E6%8A%A5" class="post-tag">早报</a>
        
        <a href="/My-Site/?tag=%E5%9B%BD%E9%99%85" class="post-tag">国际</a>
        
        <a href="/My-Site/?tag=%E5%9B%BD%E5%86%85" class="post-tag">国内</a>
        
      </div><a class="u-url" href="/My-Site/news/daily/2026/04/30/morning-news.html" hidden></a>
    </article>

    <!-- ====== Disqus 评论区 ====== -->
    <div id="disqus_thread" class="post-comments"></div>
    <script>
        var disqus_config = function () {
            this.page.url = 'https://triplejno3-alt.github.io/My-Site/news/daily/2026/04/30/morning-news.html';
            this.page.identifier = '/My-Site/news/daily/2026/04/30/morning-news.html';
        };
        (function() {
            var d = document, s = d.createElement('script');
            s.src = 'https://https-moon2dream-qzz-io.disqus.com/embed.js';
            s.setAttribute('data-timestamp', +new Date());
            (d.head || d.body).appendChild(s);
        })();
    </script>
    <noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript>
    <!-- ====== End Disqus ====== -->

  </div>

  
  <aside class="post-toc-sidebar" id="tocSidebar">
    <div class="toc-sticky">
      <div class="toc-header">📑 目录</div>
      
      
      <nav class="toc-nav" id="tocNav">
        <h1 id="-晨间新闻报告--2026年4月30日">🌅 晨间新闻报告 | 2026年4月30日</h1>

<hr />

<h2 id="-国内要闻">🇨🇳 国内要闻</h2>

<h3 id="习近平以更大力度更实举措加强基础研究">习近平:以更大力度更实举措加强基础研究</h3>

<p>中共中央总书记、国家主席、中央军委主席习近平30日上午在上海出席<strong>加强基础研究座谈会</strong>并发表重要讲话。他强调,基础研究是整个科学体系的源头,是所有技术问题的总机关。要以更大力度、更实举措加强基础研究,提升我国原始创新能力,进一步打牢科技强国建设根基。座谈会由中共中央政治局常委丁薛祥主持。</p>

<p>在”五一”国际劳动节到来之际,习近平向全国广大劳动群众致以节日祝贺和诚挚慰问。</p>

<p>同日,习近平签署第七十四号、第七十五号、第七十六号主席令。此外,《习近平谈治国理政》第五卷英文版中马读者会在马来西亚吉隆坡举行。</p>

<h3 id="十四届全国人大常委会第二十二次会议闭幕">十四届全国人大常委会第二十二次会议闭幕</h3>

<p>会议30日上午在北京人民大会堂闭幕,赵乐际委员长主持。会议表决通过了<strong>社会救助法</strong>、新修订的<strong>监狱法</strong>等多项法律案。全国人大常委会还举行了宪法宣誓仪式。</p>

<p>经本次会议决定:<strong>张柱被任命为农业农村部部长</strong><strong>张成中被任命为应急管理部部长</strong></p>

<h3 id="中央纪委通报易会满被开除党籍和公职">中央纪委通报:易会满被开除党籍和公职</h3>

<p>经中共中央批准,中央纪委国家监委对第二十届中央委员、十四届全国政协经济委员会原副主任<strong>易会满</strong>严重违纪违法问题进行了立案审查调查,决定给予其开除党籍和公职处分。</p>

<h3 id="经济数据4月制造业pmi达503">经济数据:4月制造业PMI达50.3%</h3>

<p>国家统计局、中国物流与采购联合会发布数据显示,4月份中国制造业采购经理指数为<strong>50.3%</strong>,继续位于扩张区间,制造业延续较好运行态势。</p>

<p>发改委同日透露,2026年第二批915亿元”两新”设备更新项目清单和资金安排已下达。今年已累计安排1851亿元,占全年2000亿元目标的92%。</p>

<h3 id="五一假期出行高峰来临">五一假期出行高峰来临</h3>

<p>明天是”五一”假期第一天,全国出行客流明显增加。<strong>全国铁路预计今日发送旅客1995万人次</strong>,同比增长约8.9%。京沪、京哈、京广等高铁干线安排开行夜间高铁,重点车站开启24小时通宵运营模式。</p>

<h3 id="其他国内动态">其他国内动态</h3>

<ul>
  <li>我国发布新一轮找矿突破行动成果</li>
  <li>2026年”最美职工”先进事迹发布</li>
  <li>“亮剑2026”海洋伏季休渔执法行动启动</li>
  <li>2026”世界市长对话·西安”活动举行</li>
  <li>第九届数字中国建设峰会在福州迎来公众开放日</li>
  <li>国家副主席韩正在北京会见澳大利亚外长黄英贤</li>
</ul>

<hr />

<h2 id="-国际要闻">🌍 国际要闻</h2>

<h3 id="美伊局势持续升级美军海上封锁油价飙涨超6">美伊局势持续升级:美军海上封锁,油价飙涨超6%</h3>

<p>美国总统特朗普29日表示,美方将继续对<strong>伊朗实施海上封锁</strong>,直至伊方同意达成能消除美方对伊核计划担忧的协议。伊朗议长卡利巴夫回应称,美国的海上封锁已将油价推高到每桶<strong>120美元以上</strong>,同时企图通过制造伊朗内部分裂迫使伊朗屈服,呼吁国民保持团结。</p>

<p>受此影响,<strong>国际油价29日大幅上涨超6%</strong>。媒体报道称,约2万名海员已被困霍尔木兹海峡两个月。美国民主党方面批评称,对伊动武使美国陷入泥潭。特朗普则在另一场合表示,俄乌冲突和伊朗战事”可能在同一时间表上结束”。</p>

<h3 id="以色列空袭黎巴嫩至少28人遇难">以色列空袭黎巴嫩,至少28人遇难</h3>

<p>尽管2026年以黎停火协议已达成,以色列仍于30日在黎巴嫩多地发动一系列空袭,造成<strong>至少28人死亡</strong>。中东局势依然高度紧张。</p>

<h3 id="全球新闻自由跌至25年最低">全球新闻自由跌至25年最低</h3>

<p>无国界记者组织(RSF)发布最新报告称,全球新闻自由已降至<strong>2002年指数创立以来的最低水平</strong>。超过一半的国家被归类为”严重条件”,生活在拥有强新闻自由国家的人口比例已降至不足1%。</p>

<h3 id="俄罗斯图阿普谢油港大火扑灭居民拍到油雨从天而降">俄罗斯:图阿普谢油港大火扑灭,居民拍到”油雨”从天而降</h3>

<p>俄罗斯克拉斯诺达尔边疆区图阿普谢市油港发生重大火灾,经过数日燃烧后官方宣布大火已被扑灭。然而当地居民在社交媒体上发布视频,画面显示<strong>油污如雨般从天而降</strong>,引发严重环境灾难担忧。该油港此前遭到乌克兰无人机袭击。</p>

<h3 id="俄外交部东京审判意义重大对日本军国主义罪行无诉讼时效">俄外交部:东京审判意义重大,对日本军国主义罪行无诉讼时效</h3>

<p>5月3日是远东国际军事法庭东京审判开庭80周年纪念日。俄罗斯外交部发言人表示,东京审判在法律和全人类层面都具有重要意义,对日本军国主义犯下的反人类罪行没有诉讼时效限制。韩国民众也于近日集会,谴责日本军国主义抬头。</p>

<h3 id="其他国际速览">其他国际速览</h3>

<ul>
  <li><strong>俄罗斯</strong>表示将继续在马里保持军事存在,协助马里政府打击极端主义</li>
  <li><strong>英国普利茅斯</strong>发现一枚未爆炸的二战德军SC250航空炸弹,超1000户家庭被疏散</li>
  <li><strong>威尼斯双年展</strong>国际评审团因意大利政府反对俄罗斯参展而集体辞职</li>
  <li><strong>欧元区</strong>4月经济景气指数大幅下滑</li>
  <li><strong>日本</strong>国债收益率创近30年新高</li>
  <li>美国众议院通过国土安全部拨款法案,结束了创纪录的政府部分停摆</li>
  <li>美国最高法院裁定推翻路易斯安那州国会选区地图,并削弱《民权法案》关键条款</li>
  <li>前FBI局长科米在被最新起诉后首次出庭</li>
  <li>英国国王查尔斯三世访问美国</li>
</ul>

<hr />

<h2 id="-一句话快讯">📊 一句话快讯</h2>

<ul>
  <li>中央网信办将发布《AI应用伦理安全指引1.0》,明确划定”不得诱导情感依赖”等红线</li>
  <li>特朗普在白宫接见阿尔忒弥斯二号宇航员团队</li>
  <li>阿联酋退出OPEC引发国际能源市场连锁反应</li>
  <li>全国铁路五一期间新增夜间高铁车票预售期为5至7天</li>
</ul>

<hr />

<p><em>本报告综合自新华社、央视新闻、人民网、Wikipedia Current Events、Democracy Now! 等国内外权威信源。</em></p>

<p><em>早安,这是今天的世界。</em></p>

      </nav>
      
    </div>
  </aside>
  
</div>

<style>
  .post-layout-dual {
    display: flex;
    gap: 2rem;
    justify-content: center;
    position: relative;
  }

  .post-main {
    flex: 0 1 800px;
    min-width: 0;
  }

  .post-toc-sidebar {
    flex: 0 0 240px;
    min-width: 0;
    position: relative;
  }

  .toc-sticky {
    position: sticky;
    top: 2rem;
    max-height: calc(100vh - 4rem);
    overflow-y: auto;
    padding: 0 0 1rem 0;
  }

  .toc-header {
    font-weight: 700;
    font-size: 0.95rem;
    color: var(--primary, #2c3e50);
    margin-bottom: 0.75rem;
    padding-bottom: 0.5rem;
    border-bottom: 1px solid #e5e7eb;
  }

  .toc-nav {
    font-size: 0.85rem;
    line-height: 1.6;
  }

  .toc-nav ul {
    list-style: none;
    padding: 0;
    margin: 0;
  }

  .toc-nav ul ul {
    padding-left: 1rem;
    margin-top: 0.15rem;
    margin-bottom: 0.15rem;
  }

  .toc-nav li {
    margin: 0.15rem 0;
  }

  .toc-nav a {
    display: block;
    padding: 0.2rem 0;
    color: #6b7280;
    text-decoration: none;
    border-left: 2px solid transparent;
    padding-left: 0.75rem;
    transition: all 0.15s ease;
    border-radius: 0;
  }

  .toc-nav a:hover {
    color: var(--accent, #667eea);
    border-left-color: var(--accent, #667eea);
  }

  .toc-nav a.active {
    color: var(--accent, #667eea);
    font-weight: 600;
    border-left-color: var(--accent, #667eea);
  }

  @media (max-width: 1100px) {
    .post-toc-sidebar {
      display: none;
    }
  }

  .post-toc-sidebar:empty {
    display: none;
  }

  /* ====== 代码块(post layout) ====== */
  .e-content pre {
    position: relative;
    background: #1e1e2e !important;
    color: #cdd6f4 !important;
    border-radius: 8px;
    padding: 1rem 1.25rem !important;
    font-size: 0.85rem;
    line-height: 1.6;
    overflow-x: auto;
    border: 1px solid #313244;
  }

  .e-content pre code {
    background: none !important;
    color: inherit !important;
    padding: 0 !important;
    font-family: 'JetBrains Mono', 'Fira Code', 'Cascadia Code', 'SF Mono', Consolas, monospace;
    font-size: 0.85rem;
  }

  .pre-lang-label {
    position: absolute;
    top: 0.5rem;
    left: 0.75rem;
    font-size: 0.7rem;
    color: #6c7086;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    pointer-events: none;
    z-index: 1;
  }

  .pre-copy-btn {
    position: absolute;
    top: 0.4rem;
    right: 0.75rem;
    background: none;
    border: 1px solid transparent;
    color: #6c7086;
    font-size: 0.75rem;
    cursor: pointer;
    padding: 2px 8px;
    border-radius: 4px;
    opacity: 0;
    transition: all 0.15s ease;
    z-index: 2;
  }

  pre:hover .pre-copy-btn,
  .pre-copy-btn:focus-visible {
    opacity: 1;
  }

  .pre-copy-btn:hover {
    color: #cdd6f4;
    border-color: #45475a;
    background: #313244;
  }

  .pre-copy-btn.copied {
    color: #a6e3a1;
    border-color: #a6e3a1;
  }

  pre.collapsible-code {
    max-height: none;
    cursor: default;
  }

  .pre-code-fold-btn {
    display: block;
    width: 100%;
    padding: 6px 0;
    background: #181825;
    color: #6c7086;
    font-size: 0.8rem;
    text-align: center;
    cursor: pointer;
    border: 1px solid #313244;
    border-top: none;
    border-radius: 0 0 8px 8px;
    transition: color 0.2s, background 0.2s;
    font-family: inherit;
    margin-top: -1px;
  }

  .pre-code-fold-btn:hover {
    color: #cdd6f4;
    background: #1e1e2e;
  }

  .post-header {
    margin-bottom: 2rem;
    padding-bottom: 1rem;
    border-bottom: 1px solid var(--border-color);
  }
  .post-title {
    font-size: 2.5rem;
    color: var(--primary);
    margin-bottom: 0.5rem;
  }
  .post-meta {
    color: var(--text-light);
    font-size: 0.9rem;
  }
  .post-views {
    color: var(--accent);
    font-weight: 600;
  }

  .post-tags {
    margin-top: 2.5rem;
    padding-top: 1.5rem;
    border-top: 1px solid var(--border-color);
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.5rem;
  }

  .post-tags-label {
    font-size: 0.9rem;
    color: var(--text-light);
  }

  .post-tag {
    display: inline-block;
    background: var(--tag-bg, rgba(142,150,170,0.14));
    color: var(--tag-text, #3c3c43);
    padding: 2px 10px;
    border-radius: 4px;
    font-size: 0.75rem;
    font-weight: 500;
    text-decoration: none;
    transition: background 0.2s;
  }

  .post-tag:hover {
    background: rgba(142,150,170,0.28);
  }

  /* ====== 评论区 ====== */
  .post-comments {
    margin-top: 3rem;
    padding-top: 2rem;
    border-top: 1px solid var(--border-color);
  }

  @media (max-width: 768px) {
    .post-title {
      font-size: 1.6rem;
    }
    .post-meta {
      font-size: 0.8rem;
    }
  }

  @media (max-width: 480px) {
    .post-title {
      font-size: 1.3rem;
    }
  }
</style>

<script>
document.addEventListener('DOMContentLoaded', function() {
  var tocNav = document.getElementById('tocNav');
  if (!tocNav) return;

  var links = tocNav.querySelectorAll('a');
  if (links.length === 0) return;

  var headings = [];
  links.forEach(function(link) {
    var href = link.getAttribute('href');
    if (href && href.startsWith('#')) {
      var el = document.getElementById(href.substring(1));
      if (el) headings.push({ el: el, link: link });
    }
  });

  if (headings.length === 0) {
    links.forEach(function(link) {
      var href = link.getAttribute('href');
      if (href && href.startsWith('#')) {
        var decodedId = decodeURIComponent(href.substring(1));
        var el = document.getElementById(decodedId);
        if (el) headings.push({ el: el, link: link });
      }
    });
  }

  if (headings.length === 0) return;

  function updateActiveLink() {
    var scrollY = window.scrollY + 80;
    var current = null;
    for (var i = headings.length - 1; i >= 0; i--) {
      if (headings[i].el.offsetTop <= scrollY) {
        current = headings[i];
        break;
      }
    }
    if (!current && headings.length > 0) {
      current = headings[0];
    }
    links.forEach(function(l) { l.classList.remove('active'); });
    if (current) {
      current.link.classList.add('active');
    }
  }

  setTimeout(updateActiveLink, 100);
  window.addEventListener('scroll', updateActiveLink, { passive: true });
});

// ====== 代码块样式增强:折叠 + 语言标签 + Copy ======
document.addEventListener('DOMContentLoaded', function() {
  var threshold = 40;
  var codeBlocks = document.querySelectorAll('.e-content pre');

  codeBlocks.forEach(function(pre) {
    var code = pre.querySelector('code');
    if (!code) return;

    var style = window.getComputedStyle(pre);
    if (style.position === 'static') pre.style.position = 'relative';

    var lang = '';
    code.className.split(/\s+/).forEach(function(cls) {
      var m = cls.match(/^language-(.+)$/);
      if (m) lang = m[1];
    });

    if (lang) {
      var label = document.createElement('span');
      label.className = 'pre-lang-label';
      label.textContent = lang;
      pre.appendChild(label);
    }

    var btn = document.createElement('button');
    btn.className = 'pre-copy-btn';
    btn.textContent = 'Copy';
    pre.appendChild(btn);

    btn.addEventListener('click', function(e) {
      e.stopPropagation();
      var text = code.textContent || code.innerText;
      navigator.clipboard.writeText(text).then(function() {
        btn.textContent = 'Copied!';
        btn.classList.add('copied');
        setTimeout(function() {
          btn.textContent = 'Copy';
          btn.classList.remove('copied');
        }, 2000);
      }).catch(function() {
        btn.textContent = 'Fail';
      });
    });

    var lines = code.innerHTML.split('\n');
    var start = 0, end = lines.length - 1;
    while (start < lines.length && lines[start].trim() === '') start++;
    while (end > start && lines[end].trim() === '') end--;
    var codeLineCount = Math.max(0, end - start + 1);

    if (codeLineCount < threshold) return;

    pre.classList.add('collapsible-code');

    var foldBtn = document.createElement('button');
    foldBtn.className = 'pre-code-fold-btn';
    foldBtn.textContent = '▲ 收起代码';
    pre.parentNode.insertBefore(foldBtn, pre.nextSibling);

    var isFolded = false;

    foldBtn.addEventListener('click', function(e) {
      e.stopPropagation();
      isFolded = !isFolded;
      if (isFolded) {
        code.innerHTML = lines.slice(0, start + threshold).join('\n');
        foldBtn.textContent = '▼ 展开剩余 ' + (codeLineCount - threshold) + '';
      } else {
        code.innerHTML = lines.join('\n');
        foldBtn.textContent = '▲ 收起代码';
      }
    });
  });
});
</script>

      </nav>
      
    </div>
  </aside>
  
</div>

注意这里的 toc: false 判断——不想显示目录的文章,在 frontmatter 写 toc: false 即可关闭。


一个小技巧:为什么用 sticky 而不是 fixed

position: fixed 也可以把目录固定在右侧。但有一个问题:它会脱离文档流

如果目录比文章长(极少出现,一篇文章通常比目录长得多),fixed 的目录会盖住页脚。而 sticky 就不会——它只是在父容器范围内粘性定位,当父容器(<aside>)被页脚推出屏幕时,目录也跟着滚走,不会遮住东西。

这是 stickyfixed 更优雅的根本原因。


总结

这个侧边目录的实现,说是前端技术,其实更像一个编辑器思维——把文章拆成「骨架」和「血肉」,骨架(标题)单独提取出来,放在顺手的位置,让读者随时知道自己看到哪了,想去哪里点一下就到。

所有代码加起来不到 80 行(Liquid + CSS + JS 三部分总合),但对阅读体验的提升是实打实的。下次你写博客时,不妨也加上这么一个侧边目录——有时候,一个小改进比一个大功能更让人喜欢。


本文的 TOC 就是它自己。你右手边看到的那个目录,就是你正在读的这篇文章的实现本身。

... 次阅读