The content described below is to add a garden blog directory
- You need to be compatible markdown and TinyMCE editor
- Add to active heading style
- Optional fixed position
If an error or inadequate, please correct me!
Optional configuration
catalog: {
enable: true,
position: 'left',
},
- enable whether the deprecation
- Fixed position directory location
- left fixed to the left
- the right side in right
- sidebar 'fixed effect similar to article directories Nuggets effect'
Plug-in architecture
I put the article directory integration as a plugin to the project, the following is the basic structure of the plug-in, allowing you to sort out ideas on here.
import { pageName, userAgent, hasPostTitle, getClientRect, throttle } from '@tools'
const { enable, position } = opts.catalog
// 在这里写几个 func
function catalog() {
if (conditions) return // 在入口处做一些基本的判断
// 在这里执行上面的 func
}
export default catalog
import
- pageName return to the current page name, if not the details page of the article is not necessary to execute code
- userAgent returns the user client type, mobile terminal without having to Article Directory
- hasPostTitle returns the title of the article the existence of the current article
- getClientRect return position relative to the element of the browser viewport
Construction of html
Ideas: traversing blog Campus Essay content child elements DOM, regular expressions obtained by title, create a directory html elements, and add the anchor link. Since the non-markdown editor title no id, id needs to be added when traversing its value is the title. Non markdown title content editors may not be directly nested h123 tag, it can be slightly determination process.
function build() {
let $catalogContainer = $(
`<div id="catalog">
<div class='catListTitle'><h3>目录</h3></div>
</div>`
)
const $ulContainer = $('<ul></ul>')
const titleRegExp = /^h[1-3]$/
$('#cnblogs_post_body')
.children()
.each(function () {
if (titleRegExp.test(this.tagName.toLowerCase())) {
let id
let text
if (this.id !== '') {
id = this.id
text = this.childNodes.length === 2 ? this.childNodes[1].nodeValue : this.childNodes[0].nodeValue
} else {
if (this.childNodes.length === 2) {
const value = this.childNodes[1].nodeValue
text = value ? value : $(this.childNodes[1]).text()
} else {
const value = this.childNodes[0].nodeValue
text = value ? value : $(this.childNodes[0]).text()
}
id = text.trim()
$(this).attr('id', id)
}
const title = `
<li class='${this.nodeName.toLowerCase()}-list'>
<a href='#${id}'>${text}</a>
</li>
`
$ulContainer.append(title)
}
})
$($catalogContainer.append($ulContainer)).appendTo('#sideBar')
setCatalogPosition()
}
Fixed directory
Next, the configuration according to the user's position, is fixed at the specified directory location.
function setCatalogPosition() {
const actions = {
sidebar: () => {
setCatalogToggle()
},
left: () => {
$('#catalog').addClass('catalog-sticky-left')
},
right: () => {
$('#catalog').addClass('catalog-sticky-right')
},
}
actions[position]()
}
You may adopt a more concise wording, considered here scalability, the use of such an approach.
Handling of fixed sidebar
When the directory is fixed to the sidebar, scroll to the original sidebar is not visible only display the directory location, is very simple, we only need to listen to scroll event, obtaining highly original sidebar, when it went off the screen fixed directory. Conversely, the opposite.
function setCatalogToggle() {
if (position !== 'sidebar') return
var p = 0,
t = 0
$(window).scroll(
throttle(
function () {
const bottom = getClientRect(document.querySelector('#sideBarMain')).bottom
if (bottom <= 0) {
$('#catalog').addClass('catalog-sticky')
p = $(this).scrollTop()
t <= p ? $('#catalog').addClass('catalog-scroll-up') : $('#catalog').removeClass('catalog-scroll-up')
setTimeout(function () {
t = p
}, 0)
} else {
$('#catalog').removeClass('catalog-sticky')
}
},
50,
1000 / 60
)
)
}
Add to active heading style
This step is the realization of ideas and processes in the case of fixed sidebar basically the same, when a article directory beyond the screen, we add the title to the corresponding active style on it.
function setActiveCatalogTitle() {
$(window).scroll(
throttle(
function () {
for (let i = $('#catalog ul li').length - 1; i >= 0; i--) {
const titleId = $($('#catalog ul li')[i]).find('a').attr('href').replace(/[#]/g, '')
const postTitle = document.querySelector(`#cnblogs_post_body [id='${titleId}']`)
if (getClientRect(postTitle).top <= 10) {
if ($($('#catalog ul li')[i]).hasClass('catalog-active')) return
$($('#catalog ul li')[i]).addClass('catalog-active')
$($('#catalog ul li')[i]).siblings().removeClass('catalog-active')
return
}
}
},
50,
1000 / 60
)
)
}