溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

js如何實(shí)現(xiàn)文章目錄索引導(dǎo)航

發(fā)布時(shí)間:2020-07-28 10:30:53 來(lái)源:億速云 閱讀:190 作者:小豬 欄目:web開(kāi)發(fā)

小編這次要給大家分享的是js如何實(shí)現(xiàn)文章目錄索引導(dǎo)航,文章內(nèi)容豐富,感興趣的小伙伴可以來(lái)了解一下,希望大家閱讀完這篇文章之后能夠有所收獲。

什么叫TOC呢?table of content。

具體什么效果呢?可以隨便找個(gè)hexo博客中體驗(yàn)一下,例如這個(gè)。

好了,實(shí)現(xiàn)它有2個(gè)要點(diǎn):

點(diǎn)目錄跳到段落:通過(guò)<a>標(biāo)簽的錨點(diǎn)實(shí)現(xiàn),其原理在這里。
滾動(dòng)觸發(fā)目錄變換:通過(guò)js監(jiān)聽(tīng)滾動(dòng)事件,判定當(dāng)前所處段落,令對(duì)應(yīng)目錄項(xiàng)高亮

實(shí)現(xiàn)分析

#toc是左側(cè)的目錄,#content是右側(cè)的文章正文。

 <div id="toc">
  <ul>

  </ul>
 </div>
 <div id="content">
  <a name="seg-1" class="seg-begin"><h2>第1章節(jié)</h2></a>
  <div class="seg-content"></div>
  <a name="seg-2" class="seg-begin"><h2>第2章節(jié)</h2></a>
  <div class="seg-content"></div>
  <a name="seg-3" class="seg-begin"><h2>第3章節(jié)</h2></a>
  <div class="seg-content"></div>
  <a name="seg-4" class="seg-begin"><h2>第4章節(jié)</h2></a>
  <div class="seg-content"></div>
 </div>

利用css控制#toc靠左,當(dāng)前目錄高亮為紅色,正文則靠右填滿(mǎn)屏幕:

  #toc {
   width: 200px;
   position: fixed;
   left: 0;
   top: 0;
  }
  #toc a.active {
   color: red;
  }
  #content {
   margin-left: 200px;
  }

在上面的靜態(tài)頁(yè)面中,目錄暫時(shí)為空,因?yàn)樾枰肑S動(dòng)態(tài)生成。

正文中需要人工埋點(diǎn)段落起始標(biāo)識(shí),也就是a.seg-begin這樣的錨點(diǎn),每個(gè)段落的錨點(diǎn)name唯一,而錨點(diǎn)之后緊隨段落的內(nèi)容。

在JS中,我首先按錨點(diǎn)的出現(xiàn)次序收集所有的a.seg-begin保存到segs數(shù)組中,其順序就是文章自上而下的閱讀順序,按照其<h2>中的段落標(biāo)題建出#toc中的<ul>列表:

    var segs = [];
    $(".seg-begin").each(function (idx, node) {
     segs.push(node)
     var link = $("<a></a>").attr("href", "#" + $(node).attr("name")).html($(node).children("h2").html())
     if (!idx) {
      link.addClass("active")
     }
     var row = $("<li></li>").append(link)
     $("#toc ul").append(row)
    })

然后綁定瀏覽器的scroll事件進(jìn)行監(jiān)聽(tīng),每次滾動(dòng)就判斷最近一個(gè)滾出屏幕頂部的a.seg-begin節(jié)點(diǎn),它就是當(dāng)前正在閱讀的段落:

$(window).bind("scroll", function() {
     var scrollTop = $(this).scrollTop()
     var topSeg = null
     for (var idx in segs) {
      var seg = segs[idx]
      if (seg.offsetTop > scrollTop) {
       continue
      }
      if (!topSeg) {
       topSeg = seg
      } else if (seg.offsetTop >= topSeg.offsetTop) {
       topSeg = seg
      }
     }
     if (topSeg) {
      $("#toc a").removeClass("active")
      var link = "#" + $(topSeg).attr("name")
      console.log('#toc a[href="' + link + '" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" ]')
      $('#toc a[href="' + link + '" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" ]').addClass("active")
      // console.log($(topSeg).children("h2").text())
     }
    })

后續(xù)

這里目錄的生成是在前端JS里根據(jù)正文的錨點(diǎn)動(dòng)態(tài)生成的,為了SEO可以在后端提交文章正文時(shí)匹配出這些錨點(diǎn),直接保存為目錄。

完整代碼

<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <style>
  * {
   margin: 0;
   padding: 0;
   word-break: break-all;
  }
  #toc {
   width: 200px;
   position: fixed;
   left: 0;
   top: 0;
  }
  #toc a.active {
   color: red;
  }
  #content {
   margin-left: 200px;
  }
 </style>
 <script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script>
 <script>
  $(document).ready(function () {
   for (var i = 0; i < 50; ++i) {
    $(".seg-content").append("<p>一個(gè)段落而已</p>")
   }

   (function () {
    var segs = [];
    $(".seg-begin").each(function (idx, node) {
     segs.push(node)

     var link = $("<a></a>").attr("href", "#" + $(node).attr("name")).html($(node).children("h2").html())
     if (!idx) {
      link.addClass("active")
     }
     var row = $("<li></li>").append(link)
     $("#toc ul").append(row)
    })

    $(window).bind("scroll", function() {
     var scrollTop = $(this).scrollTop()

     var topSeg = null
     for (var idx in segs) {
      var seg = segs[idx]
      if (seg.offsetTop > scrollTop) {
       continue
      }
      if (!topSeg) {
       topSeg = seg
      } else if (seg.offsetTop >= topSeg.offsetTop) {
       topSeg = seg
      }
     }
     if (topSeg) {
      $("#toc a").removeClass("active")

      var link = "#" + $(topSeg).attr("name")
      console.log('#toc a[href="' + link + '" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" ]')
      $('#toc a[href="' + link + '" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" ]').addClass("active")
      // console.log($(topSeg).children("h2").text())
     }
    })
   })()
  })
 </script>
</head>
<body>
 <div id="toc">
  <ul>

  </ul>
 </div>
 <div id="content">
  <a name="seg-1" class="seg-begin"><h2>第1章節(jié)</h2></a>
  <div class="seg-content"></div>
  <a name="seg-2" class="seg-begin"><h2>第2章節(jié)</h2></a>
  <div class="seg-content"></div>
  <a name="seg-3" class="seg-begin"><h2>第3章節(jié)</h2></a>
  <div class="seg-content"></div>
  <a name="seg-4" class="seg-begin"><h2>第4章節(jié)</h2></a>
  <div class="seg-content"></div>
 </div>
</body>
</html>

看完這篇關(guān)于js如何實(shí)現(xiàn)文章目錄索引導(dǎo)航的文章,如果覺(jué)得文章內(nèi)容寫(xiě)得不錯(cuò)的話(huà),可以把它分享出去給更多人看到。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI