<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
我的長博文不少,比較影響閱讀體驗,有必要新增一個文章目錄功能。相比 Wordpress, Typecho 的外掛就比較少了。我想找一個像掘金那樣為文章新增目錄的外掛,沒一個合適的。此類教學也不是很多,而且差不多都是前臺 JavaScript 來實現的,感覺這樣不如後臺實現來的好。
注意:我使用的是Joe主題7.3,其他主題檔案路徑可能不一樣。
1.宣告 createAnchor 函數
在 core/functions.php
中新增如下程式碼:
// 新增文章標題錨點 function createAnchor($obj) { global $catalog; global $catalog_count; $catalog = array(); $catalog_count = 0; $obj = preg_replace_callback('/<h([1-4])(.*?)>(.*?)</h1>/i', function($obj) { global $catalog; global $catalog_count; $catalog_count ++; $catalog[] = array('text' => trim(strip_tags($obj[3])), 'depth' => $obj[1], 'count' => $catalog_count); return '<h'.$obj[1].$obj[2].' id="cl-'.$catalog_count.'">'.$obj[3].'</h'.$obj[1].'>'; }, $obj); return $obj; }
也可以在標題元素內新增 <a>
標籤,然後該標籤新增 id
屬性。
createAnchor
函數主要是通過正規表示式替換文章標題H1~H4來新增錨點,接下來我們需要呼叫它。
2.呼叫函數
同樣在 core/core.php
中的 themeInit
方法最後一行之前新增如下程式碼:
if ($self->is('single')) { $self->content = createAnchor($self->content); }
現在可以檢視一下文章詳情頁面的原始碼。文章的 H1~H4
元素應該新增了諸如 cl-1
、cl-2
之類的 id
屬性值。具體啥名不是關鍵,好記就行。
1.宣告 getCatalog 函數
在 core/functions.php
中新增如下程式碼:
// 顯示文章目錄 function getCatalog() { global $catalog; $str = ''; if ($catalog) { $str = '<ul class="list">'."n"; $prev_depth = ''; $to_depth = 0; foreach($catalog as $catalog_item) { $catalog_depth = $catalog_item['depth']; if ($prev_depth) { if ($catalog_depth == $prev_depth) { $str .= '</li>'."n"; } elseif ($catalog_depth > $prev_depth) { $to_depth++; $str .= '<ul class="sub-list">'."n"; } else { $to_depth2 = ($to_depth > ($prev_depth - $catalog_depth)) ? ($prev_depth - $catalog_depth) : $to_depth; if ($to_depth2) { for ($i=0; $i<$to_depth2; $i++) { $str .= '</li>'."n".'</ul>'."n"; $to_depth--; } } $str .= '</li>'; } } $str .= '<li class="item"><a class="link" href="#cl-'.$catalog_item['count'].'" rel="external nofollow" title="'.$catalog_item['text'].'">'.$catalog_item['text'].'</a>'; $prev_depth = $catalog_item['depth']; } for ($i=0; $i<=$to_depth; $i++) { $str .= '</li>'."n".'</ul>'."n"; } $str = '<section class="toc">'."n".'<div class="title">文章目錄</div>'."n".$str.'</section>'."n"; } echo $str; }
getCatalog
方法通過遞迴 $catalog
陣列生成文章目錄,接下來我們需要呼叫它。
2.函數
最好將放在右側邊欄中。為此在 public/aside.php
中新增如下程式碼:
<?php if ($this->is('post')) getCatalog(); ?>
注意:只有文章才使用目錄,獨立頁面那些不需要,所以加了判斷。Typecho 有一些神奇的 is
語法可以方便二次開發,可以存取它的官網檔案瞭解更多。
現在點選右側的文章目錄,可以捲動到相應的文章小標題位置了。
可以看到,當前的文章目錄還比較醜陋,我們來美化一下。在 assets/css/joe.post.min.scss
中新增如下 SCSS 程式碼:
.joe_aside { .toc { position: sticky; top: 20px; width: 250px; background: var(--background); border-radius: var(--radius-wrap); box-shadow: var(--box-shadow); overflow: hidden; .title { display: block; border-bottom: 1px solid var(--classA); font-size: 16px; font-weight: 500; height: 45px; line-height: 45px; text-align: center; color: var(--theme); } .list { padding-top: 10px; padding-bottom: 10px; max-height: calc(100vh - 80px); overflow: auto; .link { display: block; padding: 8px 16px; border-left: 4px solid transparent; color: var(--main); text-decoration: none; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; &:hover { background-color: var(--classC); } &.active { border-left-color: var(--theme); } } } } }
為了方便操作,將 .toc
設定成 position: sticky;
實現了吸頂定位。考慮到文章目錄可能很多,為 .toc
列表新增了 overflow: auto;
,如程式碼第 3 ~ 4
行。
由於 .joe_header
(主題檔頭)也使用了吸頂定位,導致和文章目錄有遮擋,所有加了 has_toc .joe_header
來取消頁面主題檔頭的吸頂功能,如下程式碼:
.has_toc { .joe_header { position: relative; } }
要顯示文章目錄當前選中項的狀態,需要用到 JavaScript 給選中項新增一個 active
樣式。在 assets/js/joe.post_page.js
中新增如下程式碼:
var headings = $('.joe_detail__article').find('h1, h2, h3, h4'); var links = $('.toc .link'); var tocList = document.querySelector('.tocr > .list'); var itemHeight = $('.toc .item').height(); var distance = tocList.scrollHeight - tocList.clientHeight; var timer = 0; // 是否自動捲動 var autoScrolling = true; function setItemActive(id) { links.removeClass('active'); var link = links.filter("[href='#" + id + "']") link.addClass('active'); } function onChange() { autoScrolling = true; if (location.hash) { id = location.hash.substr(1); var heading = headings.filter("[id='" + id + "']"); var top = heading.offset().top - 15; window.scrollTo({ top: top }) setItemActive(id) } } window.addEventListener('hashchange', onChange); // hash沒有改變時手動呼叫一次 onChange();
由於佈局和捲動動畫的影響,導致錨點定位有點偏差。我們再 setItemActive
函數中用 scrollTo
或 scrollIntoView
來糾正。另外,我們希望有錨點的連結可以直接定位,因此監聽了 hashchange
事件。點選文章目錄測試一下定位,再手動鍵入錨點測試一下,應該都沒啥問題。
目前可以從文章目錄定位到文章標題了,是單向定位,雙向定位還需要實現捲動文章內容時定位到文章目錄的當前項。正如我們馬上能想到的,需要監聽 window
的 scroll
事件,如下程式碼:
function onScroll() { if (timer) { clearTimeout(timer); } timer = setTimeout(function () { var top = $(window).scrollTop(); var count = headings.length; for (var i = 0; i < count; i++) { var j = i; // 捲動和點選時 index 相差 1,需要 autoScrolling 來區分 if (i > 0 && !autoScrolling) { j = i - 1; } var headingTop = $(headings[i]).offset().top; var listTop = distance * i / count // 判斷卷軸捲動距離是否大於當前捲動項可捲動距離 if (headingTop > top) { var id = $(headings[j]).attr('id'); setItemActive(id); // 如果目錄列表有滑條,使被選中的下一元素可見 if (listTop > 0) { // 向上捲動 if (listTop < itemHeight) { listTop -= itemHeight; } else { listTop += itemHeight; } $(tocList).scrollTop(listTop) } break; } else if (i === count - 1) { // 特殊處理最後一個元素 var id = $(headings[i]).attr('id'); setItemActive(id); if (listTop > 0) { $(tocList).scrollTop(distance) } } } autoScrolling = false; }, 100); } $(window).on('scroll', onScroll);
首先,在 onScroll
事件處理常式中遍歷標題陣列 headings
, 如果卷軸捲動距離 top
大於當前標題項 item
可捲動距離 headingTop
,再呼叫 setItemActive
函數,傳入當前的標題項的 id
來判斷文章目錄啟用狀態。
如果目錄列表有滑條,呼叫 jQuery 的 scrollTop
方法捲動目錄列表滑條,使被選中目錄項的上下元素可見,
現在文章目錄基本上可用了,也還美觀,後續可以考慮優化再封裝成一個外掛。
吐槽一下:Joe 主題太依賴jQuery了,修改起來費勁 ::(汗)。
到此這篇關於Typecho外掛實現新增文章目錄的方法詳解的文章就介紹到這了,更多相關Typecho新增文章目錄內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45