欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Typecho插件實(shí)現(xiàn)添加文章目錄的方法詳解

 更新時(shí)間:2023年02月19日 14:36:30   作者:RIA愛好者  
這篇文章主要為大家詳細(xì)介紹了如何實(shí)現(xiàn)為Typecho插件實(shí)現(xiàn)添加文章目錄的功能,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,需要的可以參考一下

我的長博文不少,比較影響閱讀體驗(yàn),有必要添加一個(gè)文章目錄功能。相比 Wordpress, Typecho 的插件就比較少了。我想找一個(gè)像掘金那樣為文章添加目錄的插件,沒一個(gè)合適的。此類教程也不是很多,而且差不多都是前臺(tái) JavaScript 來實(shí)現(xiàn)的,感覺這樣不如后臺(tái)實(shí)現(xiàn)來的好。

注意:我使用的是Joe主題7.3,其他主題文件路徑可能不一樣。

添加文章標(biāo)題錨點(diǎn)

1.聲明 createAnchor 函數(shù)

core/functions.php 中添加如下代碼:

// 添加文章標(biāo)題錨點(diǎn)
function createAnchor($obj) {
  global $catalog;
  global $catalog_count;
  $catalog = array();
  $catalog_count = 0;
  $obj = preg_replace_callback('/<h([1-4])(.*?)>(.*?)<\/h\1>/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;
}

也可以在標(biāo)題元素內(nèi)添加 <a> 標(biāo)簽,然后該標(biāo)簽新增 id 屬性。

createAnchor 函數(shù)主要是通過正則表達(dá)式替換文章標(biāo)題H1~H4來添加錨點(diǎn),接下來我們需要調(diào)用它。

2.調(diào)用函數(shù)

同樣在 core/core.php 中的 themeInit 方法最后一行之前添加如下代碼:

if ($self->is('single')) {
  $self->content = createAnchor($self->content);
}

現(xiàn)在可以查看一下文章詳情頁面的源代碼。文章的 H1~H4 元素應(yīng)該添加了諸如 cl-1、cl-2 之類的 id 屬性值。具體啥名不是關(guān)鍵,好記就行。

顯示文章目錄

1.聲明 getCatalog 函數(shù)

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 數(shù)組生成文章目錄,接下來我們需要調(diào)用它。

2.函數(shù)

最好將放在右側(cè)邊欄中。為此在 public/aside.php 中添加如下代碼:

<?php if ($this->is('post')) getCatalog(); ?>

注意:只有文章才使用目錄,獨(dú)立頁面那些不需要,所以加了判斷。Typecho 有一些神奇的 is 語法可以方便二次開發(fā),可以訪問它的官網(wǎng)文檔了解更多。

現(xiàn)在點(diǎn)擊右側(cè)的文章目錄,可以滾動(dòng)到相應(yīng)的文章小標(biāo)題位置了。

添加文章目錄樣式

可以看到,當(dāng)前的文章目錄還比較丑陋,我們來美化一下。在 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 設(shè)置成 position: sticky; 實(shí)現(xiàn)了吸頂定位。考慮到文章目錄可能很多,為 .toc 列表添加了 overflow: auto;,如代碼第 3 ~ 4 行。

由于 .joe_header(主題標(biāo)頭)也使用了吸頂定位,導(dǎo)致和文章目錄有遮擋,所有加了 has_toc .joe_header 來取消頁面主題標(biāo)頭的吸頂功能,如下代碼:

.has_toc {
  .joe_header {
    position: relative;
  }
}

定位到文章

要顯示文章目錄當(dāng)前選中項(xiàng)的狀態(tài),需要用到 JavaScript 給選中項(xiàng)添加一個(gè) 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;
// 是否自動(dòng)滾動(dòng)
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沒有改變時(shí)手動(dòng)調(diào)用一次
onChange();

由于布局和滾動(dòng)動(dòng)畫的影響,導(dǎo)致錨點(diǎn)定位有點(diǎn)偏差。我們?cè)?setItemActive 函數(shù)中用 scrollToscrollIntoView 來糾正。另外,我們希望有錨點(diǎn)的鏈接可以直接定位,因此監(jiān)聽了 hashchange 事件。點(diǎn)擊文章目錄測(cè)試一下定位,再手動(dòng)鍵入錨點(diǎn)測(cè)試一下,應(yīng)該都沒啥問題。

定位到目錄

目前可以從文章目錄定位到文章標(biāo)題了,是單向定位,雙向定位還需要實(shí)現(xiàn)滾動(dòng)文章內(nèi)容時(shí)定位到文章目錄的當(dāng)前項(xiàng)。正如我們馬上能想到的,需要監(jiān)聽 windowscroll 事件,如下代碼:

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;
      // 滾動(dòng)和點(diǎn)擊時(shí) index 相差 1,需要 autoScrolling 來區(qū)分
      if (i > 0 && !autoScrolling) {
        j = i - 1;
      }
      var headingTop = $(headings[i]).offset().top;
      var listTop = distance * i / count
      // 判斷滾動(dòng)條滾動(dòng)距離是否大于當(dāng)前滾動(dòng)項(xiàng)可滾動(dòng)距離
      if (headingTop > top) {
        var id = $(headings[j]).attr('id');
        setItemActive(id);
        // 如果目錄列表有滑條,使被選中的下一元素可見
        if (listTop > 0) {
          // 向上滾動(dòng)
          if (listTop < itemHeight) {
            listTop -= itemHeight;
          } else {
            listTop += itemHeight;
          }
          $(tocList).scrollTop(listTop)
        }
        break;
      } else if (i === count - 1) {
        // 特殊處理最后一個(gè)元素
        var id = $(headings[i]).attr('id');
        setItemActive(id);
        if (listTop > 0) {
          $(tocList).scrollTop(distance)
        }
      }
    }
    autoScrolling = false;
  }, 100);
}

$(window).on('scroll', onScroll);

首先,在 onScroll 事件處理函數(shù)中遍歷標(biāo)題數(shù)組 headings, 如果滾動(dòng)條滾動(dòng)距離 top 大于當(dāng)前標(biāo)題項(xiàng) item 可滾動(dòng)距離 headingTop,再調(diào)用 setItemActive 函數(shù),傳入當(dāng)前的標(biāo)題項(xiàng)的 id 來判斷文章目錄激活狀態(tài)。

如果目錄列表有滑條,調(diào)用 jQuery 的 scrollTop 方法滾動(dòng)目錄列表滑條,使被選中目錄項(xiàng)的上下元素可見,

現(xiàn)在文章目錄基本上可用了,也還美觀,后續(xù)可以考慮優(yōu)化再封裝成一個(gè)插件。

吐槽一下:Joe 主題太依賴jQuery了,修改起來費(fèi)勁 ::(汗)。

到此這篇關(guān)于Typecho插件實(shí)現(xiàn)添加文章目錄的方法詳解的文章就介紹到這了,更多相關(guān)Typecho添加文章目錄內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論