MenuTree 是一个嵌入式文章内容目录树插件,可使用短代码标签或模板函数自定显示位置。目前,在 Typecho-Fans 插件目录中有收集,我使用的是 v0.1.2 社区维护版,其他版本没有去尝试了。

一、引入插件

参照插件的使用说明操作即可。

  1. 下载本插件,放在 usr/plugins/ 目录中,确保文件夹名为 MenuTree
  2. 激活插件,设置内可开关“嵌入模式”即文章标签输出,“独立模式”即模板函数输出;
  3. “嵌入模式”勾选时,编辑文章用按钮插入或手写< !-- index-menu -->标签发布即可显示目录树;
  4. “独立模式”勾选时,修改模板文件如 post.php 中写入 <?php $this->treeMenu(); ?> 也可显示。

我是使用的“独立模式”,在模板文件中写入 <?php $this->treeMenu(); ?> 来实现的。

二、样式修改

插件仅输出 html 不带 css,需根据以下 class 命名自行处理样式:

    .index-menu         容器 div
    .index-menu-list    列表 ul
    .index-menu-item    列表项 li
    .index-menu-link    列表项链接 a
    .menu-target-fix {display:block; position:relative; top:-60px; //偏移量}    //锚点跳转定位

这个比较好设置,比如,我目前使用的是 tailwindcss ,在主 css 文件中插入的代码是这样的:

  /* MenuTree插件需要的样式 */
  /* 目录容器 */
  .index-menu {
    @apply flex-1;
    @apply flex;
    @apply flex-col;
    @apply w-full;
    @apply -ml-2;
  }

  /* 列表 ul */
  .index-menu .index-menu-list {
    @apply flex-1;
    @apply flex;
    @apply flex-col;
    @apply ml-2;
    @apply my-1;
  }

  /* 列表项 li */
  .index-menu .index-menu-item {
    @apply flex-1;
    @apply flex;
    @apply flex-col;
    @apply ml-2;
    @apply my-1;
    @apply overflow-hidden;
  }

  /* 列表项链接 a */
  .index-menu .index-menu-link {
    @apply flex-1;
    @apply flex;
    @apply mx-auto;
    @apply w-full;
    @apply hover:text-blue-400;
    @apply hover:bg-slate-200;
    @apply dark:hover:bg-slate-600;
    @apply line-clamp-1;
  }

  /* 当前锚点 */
  .index-menu .current {
    @apply bg-slate-200;
    @apply dark:bg-slate-600;
  }

三、给目录加上高亮/动态跟踪目录效果

因为水平有限,这个功能网上找资料搞了半天,终于解决了,代码不多。在js 文件中插入下面代码:

// ------ MenuTree 插件文章目录树动态高亮-----//
//参考:https://blog.csdn.net/qq_43684588/article/details/125048254

// 滚动监听,找到锚点后,将对应的文章目录增加一个 current 的类
document.addEventListener("scroll", function () {
  const sections = document.querySelectorAll(".menu-target-fix"); //
  const scroll = document.documentElement.scrollTop || document.body.scrollTop;
  for (let i = sections.length - 1; i >= 0; i--) {
    if (parseInt(scroll) >= Math.ceil(sections[i].offsetTop) - 10) {
      activeLoadScroll(i);
      return
    }
  }
});

// 增加current 类的函数,参数为文章所有锚点的索引值
function activeLoadScroll(indexid) {
  const i = indexid;
  const categoryDomA = document.querySelectorAll("#tocbox .index-menu a");

  for (let j = 0; j <= categoryDomA.length - 1; j++) {
    if (j == i) {
      categoryDomA[j].classList.add("current");
    } else {
      categoryDomA[j].classList.remove("current");
    }
  }
}

效果正如本文右侧的目录树。