学习
实践
活动
工具
TVP
写文章
专栏首页Api实践[Typecho小试牛刀]Joe主题增加文章目录(非插件方式)
原创

[Typecho小试牛刀]Joe主题增加文章目录(非插件方式)

背景: joe主题没有目录功能,想要 目标:能自动创建文章目录,支持显示H1-H3共3级标题;标题和目录可以联动

效果:

效果图

话不多说,上代码!

修改php文件

  • 需要修改的文件: /usr/themes/Joe/public/aside.php
  • aside.php 的合适位置增加如下代码,用于在侧边栏创建目录容器
# 仅在文章和页面生效
<?php if (($this->is('post') || $this->is('page')) : ?>
    <section class="joe_aside__item catalogue">
        <div class="joe_aside__item-title">
            <svg class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2084" width="18" height="18"><path d="M640 192H224c-17.7 0-32-14.3-32-32s14.3-32 32-32h416c17.7 0 32 14.3 32 32s-14.3 32-32 32zM960 544H224c-17.7 0-32-14.3-32-32s14.3-32 32-32h736c17.7 0 32 14.3 32 32s-14.3 32-32 32zM640 896H224c-17.7 0-32-14.3-32-32s14.3-32 32-32h416c17.7 0 32 14.3 32 32s-14.3 32-32 32zM96 192H64c-17.7 0-32-14.3-32-32s14.3-32 32-32h32c17.7 0 32 14.3 32 32s-14.3 32-32 32zM96 544H64c-17.7 0-32-14.3-32-32s14.3-32 32-32h32c17.7 0 32 14.3 32 32s-14.3 32-32 32zM96 896H64c-17.7 0-32-14.3-32-32s14.3-32 32-32h32c17.7 0 32 14.3 32 32s-14.3 32-32 32z" p-id="2085"></path></svg>
            <span class="text">目录</span>
            <span class="line"></span>
        </div>
        <div class="joe_aside__item-contain">
            <ul class="catalogue-items">
            </ul>
        </div>
    </section>
<?php endif; ?>

增加js代码

  • 下面的js可以直接在Joe主题的设置中添加
  • 位置:控制台->外观->设置外观->全局设置->自定义js
function get_catalogs(article_content) {
    const titleTag = ["H1", "H2", "H3"];
    let titles = [];
    article_content.childNodes.forEach((e, index) => {
        const id = "header-" + index;
		if(titleTag.includes(e.nodeName)){
			titles.push({
                id: id,
                text: e.textContent,
                level: Number(e.nodeName.substring(1, 2))
            });
            e.setAttribute("id", id);
		}
    });
    return titles;
}
// 找到目录容器
article_content = document.querySelector('.joe_detail__article');
if (article_content) {
    var catalog = get_catalogs(article_content);
    if (catalog.length == 0) {
        // 无目录,隐藏
        $('.catalogue').hide();
    } else {
        let catalogue = '';
        for (let i = 0; i < catalog.length; i++) {
            let node = '<li class="catalogue-item"><a href="javascript:;" id="to-' + catalog[i].id + '" to="' + catalog[i].id + '" title="' + catalog[i].text + '">' + catalog[i].text + '</a>';
            if (i == catalog.length - 1) {
                catalogue += node + '</li>'
            } else {
                if (catalog[i + 1].level == catalog[i].level) {
                    catalogue += node + '</li>';
                } else if (catalog[i + 1].level > catalog[i].level) {
                    catalogue += (catalog[i + 1].level > 1) ? node + '<ul class="level-' + catalog[i + 1].level + '">' : node + '</li>';
                } else {
                    if (catalog[i + 1].level - catalog[i].level == -2) {
                        catalogue += i > 1 ? node + '</li></ul></li></ul></li>' : node + '</li></ul></li>';
                    } else {
                        catalogue += i > 1 ? node + '</li></ul></li>' : node + '</li>';
                    }

                }
            }
        }
        document.querySelector('.catalogue-items').innerHTML = catalogue;
        $('.catalogue-item > a').on('mouseenter', function () {
            $(this).parent().addClass('_active');
        });
        $('.catalogue-item > a').on('mouseleave', function () {
            $(this).parent().removeClass('_active');
        });
		// 根据目录定位到标题
        $('.catalogue-item > a').on('click', function () {
            document.removeEventListener("scroll", autoActive);
            $('.catalogue-item').removeClass('active');
            $(this).parent().addClass('active');
            let aim = document.querySelector('#' + $(this).attr('to'));
            let aim_top = aim.offsetTop;
            let aim_h = aim.clientHeight;
            let above_h = document.querySelector('.joe_header__above').clientHeight;
            let below_h = document.querySelector('.joe_header__below').clientHeight;
            let offset = 0;
            let case1 = !document.querySelector('.joe_header__above').className.includes('active');
            let case2 = document.getElementsByTagName("html")[0].scrollTop + above_h > aim_top;
            if (case1 && case2) {
                offset = above_h;
            }
            window.scrollTo({
                top: aim_top - offset - below_h - 10,
                behavior: 'smooth'
            });
            setTimeout(() => {
                document.addEventListener("scroll", autoActive);
            }, 500);
        });
        if (catalog.length)
            $('.catalogue-item').eq(0).addClass('active');
		// 目录侧标题自动定位
        let autoActive = function () {
            let html_top = document.getElementsByTagName("html")[0].scrollTop; //获得父级卷去的高度
            for (let i = 0; i < catalog.length; i++) {
                let offset = 0;
                let h_id = '#' + catalog[i].id;
                let h_offset = document.querySelector(h_id).offsetTop;
                let above_h = document.querySelector('.joe_header__above').clientHeight;
                let below_h = document.querySelector('.joe_header__below').clientHeight;

                if (!document.querySelector('.joe_header').className.includes('active'))
                    offset = above_h;
                if (h_offset + below_h + offset + 10 >= html_top) {
                    $('.catalogue-item').removeClass('active');
                    if (i > 0 && i < catalog.length - 1 && document.querySelector('#' + catalog[i].id).offsetTop > html_top + window.innerHeight * 0.2) {
                        //还没到下一个标题
                        i--;
                    }
                    $('#to-' + catalog[i].id).parent().addClass('active');
                    break;
                }
            }
        };
        document.addEventListener("scroll", autoActive);
    }
} else {
    // 不是文章,隐藏目录
    $('.catalogue').hide();
}

css样式表

  • 样式表同js,也可以在Joe主题的设置中添加
  • 位置: 控制台->外观->设置外观->全局设置->自定义css
  • 以下样式表是我自己博客使用的,仅供参考
.joe_aside__item.catalogue {
    z-index: 999;
    position: sticky;
    top: 45px;
    margin-bottom: 15px;
    transition: top 0.35s;
    background: var(--background)
}
.joe_aside__item.catalogue .joe_aside__item-contain  {
    padding: 0;
    margin: 0;
    margin-left: 10px
}
.joe_aside__item.catalogue .joe_aside__item-contain .catalogue-items {
    border-left: 1px solid var(--classC);
    border-bottom: 1px solid var(--background);
    padding: 15px
}
.joe_aside__item.catalogue .joe_aside__item-contain .catalogue-items .catalogue-item {
    margin: 0;
    padding: 0;
    line-height: 26px;
    font-size: 16px
}
.joe_aside__item.catalogue .joe_aside__item-contain .catalogue-items .catalogue-item a {
    position: relative;
    display: block;
    line-height: 26px;
    color: var(--main);
    transition: color 0.5s
}
.joe_aside__item.catalogue .joe_aside__item-contain .catalogue-items .catalogue-item a: hover {
    color: var(--theme)
}
.joe_aside__item.catalogue .joe_aside__item-contain .catalogue-items .catalogue-item._active>a, .joe_aside__item.catalogue .joe_aside__item-contain .catalogue-items .catalogue-item.active>a {
    color: var(--theme)
}
.joe_aside__item.catalogue .joe_aside__item-contain .catalogue-items .catalogue-item._active>a::before, .joe_aside__item.catalogue .joe_aside__item-contain .catalogue-items .catalogue-item.active>a::before {
    content: "";
    position: absolute;
    left: -17px;
    top: 0;
    width: 2px;
    height: 26px;
    background-color: var(--theme);
    transition: height 0.35s
}
.joe_aside__item.catalogue .joe_aside__item-contain .catalogue-items .catalogue-item .level-2.catalogue-item, .joe_aside__item.catalogue .joe_aside__item-contain .catalogue-items .catalogue-item .level-3 .catalogue-item {
    font-size: 14px
}
.joe_aside__item.catalogue .joe_aside__item-contain .catalogue-items .catalogue-item .level-2 .catalogue-item._active>a::before, .joe_aside__item.catalogue .joe_aside__item-contain .catalogue-items .catalogue-item .level-2 .catalogue-item.active>a::before, .joe_aside__item.catalogue .joe_aside__item-contain .catalogue-items .catalogue-item .level-3 .catalogue-item._active>a::before, .joe_aside__item.catalogue .joe_aside__item-contain .catalogue-items .catalogue-item .level-3 .catalogue-item.active>a::before {
    left: -34px
}
.joe_aside__item.catalogue .joe_aside__item-contain .catalogue-items .catalogue-item .level-2 .catalogue-item .level-3 .catalogue-item, .joe_aside__item.catalogue .joe_aside__item-contain .catalogue-items .catalogue-item .level-3 .catalogue-item .level-3 .catalogue-item {
    font-size: 12px
}
.joe_aside__item.catalogue .joe_aside__item-contain .catalogue-items .catalogue-item .level-2 .catalogue-item .level-3 .catalogue-item._active>a::before, .joe_aside__item.catalogue .joe_aside__item-contain .catalogue-items .catalogue-item .level-2 .catalogue-item .level-3 .catalogue-item.active>a::before, .joe_aside__item.catalogue .joe_aside__item-contain .catalogue-items .catalogue-item .level-3 .catalogue-item .level-3 .catalogue-item._active>a::before, .joe_aside__item.catalogue .joe_aside__item-contain .catalogue-items .catalogue-item .level-3 .catalogue-item .level-3 .catalogue-item.active>a::before {
    left: -51px
}
.joe_aside__item.catalogue .joe_aside__item-contain .catalogue-items .catalogue-item .level-3 .catalogue-item {
    font-size: 12px
}
.joe_aside__item.catalogue .joe_aside__item-contain .catalogue-items .catalogue-item ul {
    padding-left: 17px
}
.joe_aside__item.catalogue .joe_aside__item-contain .catalogue-items ul {
    display: block;
    list-style-type: disc
}
  • 提醒:假如后期升级Joe主题,记得重新修改 aside.php
  • 理论上也适用于其他主题,只是需要修改的文件不同

笔者为腾讯云TDP成员,点击加入腾讯云TDP

原文链接:https://nongxue.top/p/daima/60.html

原创声明,本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

登录 后参与评论
0 条评论

相关文章

  • [Typecho小试牛刀]Joe主题增加验证码(非插件方式)

    刚刚接触Typecho,发现Joe主题不错,摸索了两天之后,发现Joe本身不支持评论验证码,就查阅资料,修改部分Joe主题文件,增加评论验证码。

    TDP-苏苏
  • [Typecho小试牛刀]给Joe编辑器增加热键

    TDP-苏苏
  • Joe一款基于Typecho博客的双栏极致优化主题

    Github下载地址:HaoOuBa/Joe: A Theme of Typecho (github.com)

    一只无聊的清风
  • typecho博客配置腾讯云对象存储COS加速

    采用Joe主题的typecho的博客运行也有一段时间了。最近发现访问不太稳定,等很长时间都打不开,用chrome调试工具发现cdn.jsdelivr.net长时...

    IT不难
  • Typecho微信公众号验证码涨粉丝插件(美化版)-星泽V社

    一款利于微信公众号涨粉的Typecho插件 访客必须关注 公众号 获取验证码,然后输入验证码才能看到内容

    星泽V社
  • Onecircle基于Typecho的圈子主题

    v1.6 支持 pjax,以及前台登录发布文章,加入progress动画 v1.7 bugs fix v1.8 gallery 支持,优化前台图片显示,后台添加...

    一只无聊的清风
  • Typecho邮件通知类插件 LoveKKCommentModify-星泽V社

    LoveKKCommentModify是一款Typecho邮件通知类插件,支持SMTP、Send Cloud、阿里云邮件推送三种邮件通知方式。

    星泽V社
  • Typecho自定义编辑器功能

    首先在你的主题 functions.php 里增加一个插件函数,这个函数的用途是在编辑文章和编辑页面里面引入自定义JS

    用户7146828
  • 使用RuleUser接管Typecho用户中心教程 - 星泽V社

    RuleUser通过API的方式完全接管typecho的用户系统,让Typecho网站拥有一个独立会员中心的同时,还可以将前台用户的操作全部API化。 具体演示...

    星泽V社
  • Mirages主题帮助文档

    将压缩包内1.主题文件文件夹中的Mirages文件夹完整上传到服务器上 Typecho 的/usr/themes/文件夹内,然后到 Typecho 后台,启用主...

    乐心湖
  • 记从Hexo迁移到Typecho

    从2016年4月24号开始,我的博客从WordPress迁移至Hexo。当时Hexo算是当红炸子鸡,原生支持Markdown语法,支持静态部署,支持各种插件,还...

    zhangheng
  • Typecho文章代码高亮功能

    Typecho是一款由国人开发的博客程序,它的特点是简洁小巧,扩展性强,并且内置支持Markdown语法写作,因而很受技术博客作者的欢迎。但是默认的Typec...

    HCG_Sky
  • Typecho主题设置总结

    wordpress用了很久了,总是感觉网站访问速度慢,又不能搞什么大事情,于是乎该折腾就折腾换到Typecho,简约的风格,虽然是动态php但是不臃肿,访问速度...

    saucerman
  • 提升Typecho首页ttfb加载速度以及若干升级

    查看主题的index.php找header,顺势找到header.php文件,你会在<header></header>看到如下代码: <link rel="i...

    西柚dzh
  • Typecho生成网站地图 Sitemap.XML插件-星泽V社

    前言 sitemap,又叫站点地图,我之前看过好多博客网站里面都没有做这个,都忽略了站点地图的作用。站点地图就相当于是一个网页目录,它可以很直观的将网站的构架...

    星泽V社
  • 从零开始折腾博客(4):从Wordpress迁移到Typecho

    思考了很久,最终决定从Wordpress迁移到Typecho。 我承认,Wordpress是一个强大的建站工具,但是不太像博客了。 搜索主题,搜索插件,得到的太...

    idealclover
  • Typecho社会化登录插件TeConnect安装及回调问题解决

    我在上一边文章《QQ互联平台个人开发者认证》中像大家介绍了QQ互联的认证,获取APP ID 和 APP Key的方法,同时也给大家推荐了一款免费的第三方登录插件...

    梦溪
  • 博客从 typecho 迁移到 Hexo

    tanmx
  • Typecho插件 - 为你的文章生成海报

    其实写这个插件的初衷还是因为——我没钱!没错,就是我没钱。其实最早是在Typecho爱好者博客里面看到的。当时感觉这个插件的确不错,我很喜欢。但是付费下载就很要...

    MoLeft

扫码关注腾讯云开发者

领取腾讯云代金券