原文連接:Bougie的博客javascript
製做目錄索引這種東西固然是放在前端方便。選擇放在後端一是爲了瞭解Node後端生態,掌握更多後端技術;二是由於公司實行先後端分離的方式開發,睾貴的JAVA後端常常啥也不作處理就返回一個row數據(甚至有時時間戳都不處理),對此有些無語。
const markDown = require('marked') markDown.setOptions({ headerIds: false, highlight: function(code) { return require('highlight.js').highlightAuto(code).value; }, }) let html = markDown(data.content)
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
知道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()
本網站的header是fixed在頂部的,錨點不進行偏移會蓋住標題。偏移方法:前端
h1, h2, h3, h4, h5, h6{ &:target{ padding-top: 60px } }