cheerio製做markDown索引目錄

原文連接:Bougie的博客javascript

製做目錄索引這種東西固然是放在前端方便。選擇放在後端一是爲了瞭解Node後端生態,掌握更多後端技術;二是由於公司實行先後端分離的方式開發,睾貴的JAVA後端常常啥也不作處理就返回一個row數據(甚至有時時間戳都不處理),對此有些無語。

image

最終目標

image

  1. 點擊索引單項跳轉到相應標題
  2. 大號標題包含小號標題,小號標題向右縮進
  3. 滾動頁面時自動切換索引項active狀態

實現方法

md轉化爲html

const markDown = require('marked')
markDown.setOptions({
    headerIds: false,
    highlight: function(code) {
        return require('highlight.js').highlightAuto(code).value;
    },
})
let html = markDown(data.content)

cheerio生成索引

const cheerio = require('cheerio')

// decodeEntities防止中文轉化爲unicdoe
const $ = cheerio.load(html,{decodeEntities: false})

// 用hNum生成自定義id
let hArr = [], highestLvl, hNum = 0
$('h1, h2, h3, h4, h5, h6').each(function () {
    let id = `h${hNum}`
    hNum++
    $(this).attr('id', id)
    let lvl = $(this).get(0).tagName.substr(1)
    if(!highestLvl) highestLvl = lvl
    hArr.push({
        lvl: lvl - highestLvl + 1,
        content: $(this).html(),
        id: id
    })
})
Object.assign(data, {
    content: $.html,
    toc: hArr
})

前臺展現

if data && data.toc
    ul#toc-wrapper.toc-wrapper-transform
      each item in data.toc
        // 利用lvl判斷偏移量
        li(class='toc-item text-elli', style=`padding-left: ${item.lvl * 15}px`, id=item.id)
          a(href=`#${item.id}`, title=item.content).text-elli= item.content

頁面滾動過自動切換active

知道getBoundingClientRect API就好作了html

function tocToggle() {
    if($('.article-content').dom.length == 0) return
    let scrollArr = []
    document.querySelectorAll('.article-content h1, h2, h3, h4, h5, h6').forEach(i => {
        let elTop = Math.abs(i.getBoundingClientRect().top)
        scrollArr.push({
            el: i,
            top: elTop
        })
    })
    if(scrollArr.length == 0) return
    scrollArr = scrollArr.sort((a, b) => {
        return a.top - b.top
    })
    let activeId = $(scrollArr[0].el).attr('id')
    $(`#toc-wrapper #${activeId}`).ac('toc-item-active').siblings().rc('toc-item-active')
}

$(window).on('scroll', () => {
    tocToggle()
})

tocToggle()

Tips

錨點偏移

本網站的header是fixed在頂部的,錨點不進行偏移會蓋住標題。偏移方法:前端

h1, h2, h3, h4, h5, h6{
    &:target{
        padding-top: 60px
    }
}
相關文章
相關標籤/搜索