如何给 Ghost 博客添加目录?图文教程

为了给文章添加目录,我们将使用一个名为 Tocbot 的 JavaScript (JS) 库。该库为我们解决了复杂的工作,其中包括查找帖子的二级、三级等标题,并为此创建文章的锚点链接以及向读者显示它们在页面上的位置。

主页 > 博客 > 如何给 Ghost 博客添加目录?图文教程

为了给文章添加目录,我们将使用一个名为 Tocbot 的 JavaScript (JS) 库。该库为我们解决了复杂的工作,其中包括查找帖子的二级、三级等标题,并为此创建文章的锚点链接以及向读者显示它们在页面上的位置。

Tocbot 的工作原理是查看帖子的标题标签,例如 <h2> ,通过选择标题文本并单击弹出编辑器中的 H 图标,在 Ghost 中创建标题。Tocbot 库由两部分组成:

  1. 处理功能的 JS 文件
  2. 处理基本样式的 CSS 文件

两者都需要加载到你的 Ghost 主题中。在本教程中,我们将使用 Ghost 的默认主题 Casper。虽然这些步骤适用于任何 Ghost 主题,但你需要修改代码才能适用于你的其它特定主题。

1.编辑default.hbs文件

在代码编辑器中打开 default.hbs ,在此文件中,添加 Tocbot 脚本和样式,如下所述。

添加 CSS

default.hbs 文件顶部附近的 head 标记中的 {{ghost_head}} 之前,添加 Tocbot CSS:

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/tocbot/4.12.3/tocbot.css">
给 Ghost 博客添加目录

添加 style 样式

同样的,上面的 CSS 链接添加后,在其后面,接着添加下面的 CSS 样式,下面的样式也是包裹在<head></head>标签里面的,不要放错地方。

<style>
.gh-content {
    position: relative;
 }

.gh-toc > .toc-list {
    position: relative;
}

.toc-list {
    overflow: hidden;
    list-style: none;
}

@media (min-width: 1300px) {
     .gh-sidebar {
        position: absolute; 
        top: 0;
        bottom: 0;
        margin-top: 4vmin;
        grid-column: wide-start / main-start; /* Place the TOC to the left of the content */
    }
   
    .gh-toc {
        position: sticky; /* On larger screens, TOC will stay in the same spot on the page */
        top: 4vmin;
    }
}

.gh-toc .is-active-link::before {
    background-color: var(--ghost-accent-color); /* Defines TOC   accent color based on Accent color set in Ghost Admin */
} 
</style>

上面的 CSS 的意思是,让目录在大屏幕上与文章内容一起显示,然后在小屏幕上显示在文章内容上方。

添加 JS

default.hbs 中,在靠近文件末尾的 {{ghost_foot}} 之前,添加 Tocbot 脚本,图见下文:

<script src="https://cdnjs.cloudflare.com/ajax/libs/tocbot/4.12.3/tocbot.min.js"></script>

初始化 Tocbot 脚本

加载 Tocbot 脚本后,我们现在需要对其进行初始化,这会告诉 Tocbot 我们想要在页面上的哪个位置放置目录以及要添加到其中的内容。引入上面的 JS 链接后,在其后面,添加下面的脚本:

{{! Initialize Tocbot after you load the script }}
<script>
    tocbot.init({
        // Where to render the table of contents.
        tocSelector: '.gh-toc',
        // Where to grab the headings to build the table of contents.
        contentSelector: '.gh-content',
        // Which headings to grab inside of the contentSelector element.
        headingSelector: 'h1, h2, h3, h4',
        // Ensure correct positioning
        hasInnerContainers: true,
    });
</script>

本教程中使用的类( gh-contentgh-toc )基于 Casper 主题。你需要更改 gh-content 以匹配主题的容器类(包含你的帖子内容)。 gh-toc 可以是你想要的任何内容,你只需确保初始化脚本中的类与模板中的类匹配。
给 Ghost 博客添加目录

2.编辑 post.hbs文件

让我们定义我们希望目录在主题中显示的位置。在 post.hbs 中,在 {{content}} 帮助器之前添加以下代码片段:

<aside class="gh-sidebar"><div class="gh-toc"></div></aside> {{! The TOC will be inserted here }}

这段代码的作用就是让目录附着在文章的左上方,跟上面添加的 CSS 文件相对应。

给 Ghost 博客添加目录

3.完整代码

作为最终检查,你的 default.hbspost.hbs 文件应如下所示:

default.hbs:

<!DOCTYPE html>
<html lang="{{@site.locale}}"{{#match @custom.color_scheme "Dark"}} class="dark-mode"{{else match @custom.color_scheme "Auto"}} class="auto-color"{{/match}}>
<head>

    {{!-- Basic meta - advanced meta is output with {ghost_head} below --}}
    <title>{{meta_title}}</title>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="HandheldFriendly" content="True" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />

    {{!-- Theme assets - use the {asset} helper to reference styles & scripts,
    this will take care of caching and cache-busting automatically --}}
    <link rel="stylesheet" type="text/css" href="{{asset "built/screen.css"}}" />
    
    {{!-- TOC styles --}}
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/tocbot/4.12.3/tocbot.css">
    
    <style>
    .gh-content {
        position: relative;
    }

    .gh-toc > .toc-list {
        position: relative;
    }

    .toc-list {
        overflow: hidden;
        list-style: none;
    }

    @media (min-width: 1300px) {
        .gh-sidebar {
            position: absolute; 
            top: 0;
            bottom: 0;
            margin-top: 4vmin;
            grid-column: wide-start / main-start; /* Place the TOC to the left of the content */
        }
    
        .gh-toc {
            position: sticky; /* On larger screens, TOC will stay in the same spot on the page */
            top: 4vmin;
        }
    }

    .gh-toc .is-active-link::before {
        background-color: var(--ghost-accent-color); /* Defines TOC accent color based on Accent color set in Ghost Admin */
    } 
    </style>

    {{!-- This tag outputs all your advanced SEO meta, structured data, and other important settings,
    it should always be the last tag before the closing head tag --}}
    {{ghost_head}}

</head>
<body class="{{body_class}}{{#match @custom.title_font "=" "Elegant serif"}} has-serif-title{{/match}}{{#match @custom.body_font "=" "Modern sans-serif"}} has-sans-body{{/match}}{{#if @custom.show_publication_cover}} has-cover{{/if}}{{#is "home"}}{{#unless @custom.show_logo_in_navigation}} no-logo{{/unless}}{{/is}}">
<div class="viewport">

    <header id="gh-head" class="gh-head outer">
        <nav class="gh-head-inner inner">

            <div class="gh-head-brand">
                <a class="gh-head-logo{{#unless @site.logo}} no-image{{/unless}}" href="{{@site.url}}">
                    {{#if @site.logo}}
                        <img src="{{@site.logo}}" alt="{{@site.title}}" />
                    {{else}}
                        {{@site.title}}
                    {{/if}}
                </a>
                <a class="gh-burger" role="button">
                    <div class="gh-burger-box">
                        <div class="gh-burger-inner"></div>
                    </div>
                </a>
            </div>
            <div class="gh-head-menu">
                {{navigation}}
            </div>
            <div class="gh-head-actions">
                <div class="gh-social">
                    {{#if @site.facebook}}
                        <a class="gh-social-link gh-social-facebook" href="{{facebook_url @site.facebook}}" title="Facebook" target="_blank" rel="noopener">{{> "icons/facebook"}}</a>
                    {{/if}}
                    {{#if @site.twitter}}
                        <a class="gh-social-link gh-social-twitter" href="{{twitter_url @site.twitter}}" title="Twitter" target="_blank" rel="noopener">{{> "icons/twitter"}}</a>
                    {{/if}}
                </div>
                {{#if @site.members_enabled}}
                    {{#unless @member}}
                        <a class="gh-head-button" href="#/portal/signup" data-portal="signup">Subscribe</a>
                    {{else}}
                        <a class="gh-head-button" href="#/portal/account" data-portal="account">Account</a>
                    {{/unless}}
                {{/if}}
            </div>
        </nav>
    </header>

    <div class="site-content">
        {{!-- All other templates get inserted here, index.hbs, post.hbs, etc --}}
        {{{body}}}
    </div>

    {{!-- The global footer at the very bottom of the screen --}}
    <footer class="site-footer outer">
        <div class="inner">
            <section class="copyright"><a href="{{@site.url}}">{{@site.title}}</a> &copy; {{date format="YYYY"}}</section>
            <nav class="site-footer-nav">
                {{navigation type="secondary"}}
            </nav>
            <div><a href="https://ghost.org/" target="_blank" rel="noopener">Powered by Ghost</a></div>
        </div>
    </footer>

</div>
{{!-- /.viewport --}}


{{!-- Scripts - handle member signups, responsive videos, infinite scroll, floating headers, and galleries --}}
<script
    src="https://code.jquery.com/jquery-3.5.1.min.js"
    integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0="
    crossorigin="anonymous">
</script>
<script src="{{asset "built/casper.js"}}"></script>
<script>
$(document).ready(function () {
    // Mobile Menu Trigger
    $('.gh-burger').click(function () {
        $('body').toggleClass('gh-head-open');
    });
    // FitVids - Makes video embeds responsive
    $(".gh-content").fitVids();
});
</script>

{{!-- Tocbot script --}}
<script src="https://cdnjs.cloudflare.com/ajax/libs/tocbot/4.12.3/tocbot.min.js"></script>

{{! Initialize Tocbot after you load the script }}
<script>
    tocbot.init({
        // Where to render the table of contents.
        tocSelector: '.gh-toc',
        // Where to grab the headings to build the table of contents.
        contentSelector: '.gh-content',
        // Which headings to grab inside of the contentSelector element.
        headingSelector: 'h1, h2, h3, h4',
        // Ensure correct positioning
        hasInnerContainers: true,
    });
</script>

{{!-- Ghost outputs required functional scripts with this tag - it should always be the last thing before the closing body tag --}}
{{ghost_foot}}

</body>
</html>

post.hbs:

{{!< default}}

{{!-- The tag above means: insert everything in this file
into the {body} tag of the default.hbs template --}}


{{#post}}
{{!-- Everything inside the #post block pulls data from the post --}}

<main id="site-main" class="site-main">
<article class="article {{post_class}} {{#match @custom.post_image_style "Full"}}image-full{{else match @custom.post_image_style "=" "Small"}}image-small{{/match}}">

    <header class="article-header gh-canvas">

        <div class="article-tag post-card-tags">
            {{#primary_tag}}
                <span class="post-card-primary-tag">
                    <a href="{{url}}">{{name}}</a>
                </span>
            {{/primary_tag}}
            {{#if featured}}
                <span class="post-card-featured">{{> "icons/fire"}} Featured</span>
            {{/if}}
        </div>

        <h1 class="article-title">{{title}}</h1>

        {{#if custom_excerpt}}
            <p class="article-excerpt">{{custom_excerpt}}</p>
        {{/if}}

        <div class="article-byline">
        <section class="article-byline-content">

            <ul class="author-list">
                {{#foreach authors}}
                <li class="author-list-item">
                    {{#if profile_image}}
                    <a href="{{url}}" class="author-avatar">
                        <img class="author-profile-image" src="{{img_url profile_image size="xs"}}" alt="{{name}}" />
                    </a>
                    {{else}}
                    <a href="{{url}}" class="author-avatar author-profile-image">{{> "icons/avatar"}}</a>
                    {{/if}}
                </li>
                {{/foreach}}
            </ul>

            <div class="article-byline-meta">
                <h4 class="author-name">{{authors}}</h4>
                <div class="byline-meta-content">
                    <time class="byline-meta-date" datetime="{{date format="YYYY-MM-DD"}}">{{date}}</time>
                    {{#if reading_time}}
                        <span class="byline-reading-time"><span class="bull">&bull;</span> {{reading_time}}</span>
                    {{/if}}
                </div>
            </div>

        </section>
        </div>

        {{#match @custom.post_image_style "!=" "Hidden"}}
        {{#if feature_image}}
            <figure class="article-image">
                {{!-- This is a responsive image, it loads different sizes depending on device
                https://medium.freecodecamp.org/a-guide-to-responsive-images-with-ready-to-use-templates-c400bd65c433 --}}
                <img
                    srcset="{{img_url feature_image size="s"}} 300w,
                            {{img_url feature_image size="m"}} 600w,
                            {{img_url feature_image size="l"}} 1000w,
                            {{img_url feature_image size="xl"}} 2000w"
                    sizes="(min-width: 1400px) 1400px, 92vw"
                    src="{{img_url feature_image size="xl"}}"
                    alt="{{#if feature_image_alt}}{{feature_image_alt}}{{else}}{{title}}{{/if}}"
                />
                {{#if feature_image_caption}}
                    <figcaption>{{feature_image_caption}}</figcaption>
                {{/if}}
            </figure>
        {{/if}}
        {{/match}}

    </header>

    <section class="gh-content gh-canvas">
        <
        <aside class="gh-sidebar"><div class="gh-toc"></div></aside> {{! The TOC will be inserted here }}
        {{content}}
    </section>

    {{!--
    <section class="article-comments gh-canvas">
        If you want to embed comments, this is a good place to paste your code!
    </section>
    --}}

</article>
</main>

{{!-- A signup call to action is displayed here, unless viewed as a logged-in member --}}
{{#if @site.members_enabled}}
{{#unless @member}}
{{#if access}}
    <section class="footer-cta outer">
        <div class="inner">
            {{#if @custom.email_signup_text}}<h2 class="footer-cta-title">{{@custom.email_signup_text}}</h2>{{/if}}
            <a class="footer-cta-button" href="#/portal" data-portal>
                <div class="footer-cta-input">Enter your email</div>
                <span>Subscribe</span>
            </a>
            {{!-- ^ This looks like a form element, but it's just a link to Portal,
            making the form validation and submission much simpler. --}}
        </div>
    </section>
{{/if}}
{{/unless}}
{{/if}}


{{!-- Read more links, just above the footer --}}
{{#if @custom.show_recent_posts_footer}}
    {{!-- The {#get} helper below fetches some of the latest posts here
    so that people have something else to read when they finish this one.

    This query gets the latest 3 posts on the site, but adds a filter to
    exclude the post we're currently on from being included. --}}
    {{#get "posts" filter="id:-{{id}}" limit="3" as |more_posts|}}

        {{#if more_posts}}
            <aside class="read-more-wrap outer">
                <div class="read-more inner">
                    {{#foreach more_posts}}
                        {{> "post-card"}}
                    {{/foreach}}
                </div>
            </aside>
        {{/if}}

    {{/get}}
{{/if}}

{{/post}}

最终,你的页面看起来大概是这样子的:

给 Ghost 博客添加目录

总结

为了添加文章目录,使用名为 Tocbot 的 JavaScript(JS)库。该库简化了复杂的工作,通过查找帖子的标题标签(如<h2>)创建目录锚点链接,方便读者查看位置。Tocbot 包含处理功能的 JS 文件和处理基本样式的 CSS 文件,需要加载到 Ghost 主题中。在教程中,以 Ghost 默认主题 Casper 为例,修改 default.hbs 文件添加 Tocbot 脚本和样式,同时在 post.hbs 中定义目录位置。

如何给 Ghost 博客添加目录?图文教程
为了给文章添加目录,我们将使用一个名为 Tocbot 的 JavaScript (JS) 库。该库为我们解决了复杂的工作,其中包括查找帖子的二级、三级等标题,并为此创建文章的锚点链接以及向读者显示它们在页面上的位置。

知识扩展: