mirror of
https://github.com/docsifyjs/docsify.git
synced 2025-12-08 19:55:52 +00:00
* Don't replace leading digit * Install css.escape * Escape leading digit of the anchor id
157 lines
3.5 KiB
JavaScript
157 lines
3.5 KiB
JavaScript
import { isMobile } from '../util/env'
|
|
import * as dom from '../util/dom'
|
|
import Tweezer from 'tweezer.js'
|
|
import cssEscape from 'css.escape'
|
|
|
|
const nav = {}
|
|
let hoverOver = false
|
|
let scroller = null
|
|
let enableScrollEvent = true
|
|
let coverHeight = 0
|
|
|
|
function scrollTo(el) {
|
|
if (scroller) {
|
|
scroller.stop()
|
|
}
|
|
|
|
enableScrollEvent = false
|
|
scroller = new Tweezer({
|
|
start: window.pageYOffset,
|
|
end: el.getBoundingClientRect().top + window.pageYOffset,
|
|
duration: 500
|
|
})
|
|
.on('tick', v => window.scrollTo(0, v))
|
|
.on('done', () => {
|
|
enableScrollEvent = true
|
|
scroller = null
|
|
})
|
|
.begin()
|
|
}
|
|
|
|
function highlight(path) {
|
|
if (!enableScrollEvent) {
|
|
return
|
|
}
|
|
|
|
const sidebar = dom.getNode('.sidebar')
|
|
const anchors = dom.findAll('.anchor')
|
|
const wrap = dom.find(sidebar, '.sidebar-nav')
|
|
let active = dom.find(sidebar, 'li.active')
|
|
const doc = document.documentElement
|
|
const top = ((doc && doc.scrollTop) || document.body.scrollTop) - coverHeight
|
|
let last
|
|
|
|
for (let i = 0, len = anchors.length; i < len; i += 1) {
|
|
const node = anchors[i]
|
|
|
|
if (node.offsetTop > top) {
|
|
if (!last) {
|
|
last = node
|
|
}
|
|
|
|
break
|
|
} else {
|
|
last = node
|
|
}
|
|
}
|
|
|
|
if (!last) {
|
|
return
|
|
}
|
|
|
|
const li = nav[getNavKey(decodeURIComponent(path), last.getAttribute('data-id'))]
|
|
|
|
if (!li || li === active) {
|
|
return
|
|
}
|
|
|
|
active && active.classList.remove('active')
|
|
li.classList.add('active')
|
|
active = li
|
|
|
|
// Scroll into view
|
|
// https://github.com/vuejs/vuejs.org/blob/master/themes/vue/source/js/common.js#L282-L297
|
|
if (!hoverOver && dom.body.classList.contains('sticky')) {
|
|
const height = sidebar.clientHeight
|
|
const curOffset = 0
|
|
const cur = active.offsetTop + active.clientHeight + 40
|
|
const isInView =
|
|
active.offsetTop >= wrap.scrollTop && cur <= wrap.scrollTop + height
|
|
const notThan = cur - curOffset < height
|
|
const top = isInView ? wrap.scrollTop : notThan ? curOffset : cur - height
|
|
|
|
sidebar.scrollTop = top
|
|
}
|
|
}
|
|
|
|
function getNavKey(path, id) {
|
|
return `${path}?id=${id}`
|
|
}
|
|
|
|
export function scrollActiveSidebar(router) {
|
|
const cover = dom.find('.cover.show')
|
|
coverHeight = cover ? cover.offsetHeight : 0
|
|
|
|
const sidebar = dom.getNode('.sidebar')
|
|
let lis = []
|
|
if (sidebar !== null && sidebar !== undefined) {
|
|
lis = dom.findAll(sidebar, 'li')
|
|
}
|
|
|
|
for (let i = 0, len = lis.length; i < len; i += 1) {
|
|
const li = lis[i]
|
|
const a = li.querySelector('a')
|
|
if (!a) {
|
|
continue
|
|
}
|
|
|
|
let href = a.getAttribute('href')
|
|
|
|
if (href !== '/') {
|
|
const { query: { id }, path } = router.parse(href)
|
|
if (id) {
|
|
href = getNavKey(path, id)
|
|
}
|
|
}
|
|
|
|
if (href) {
|
|
nav[decodeURIComponent(href)] = li
|
|
}
|
|
}
|
|
|
|
if (isMobile) {
|
|
return
|
|
}
|
|
|
|
const path = router.getCurrentPath()
|
|
dom.off('scroll', () => highlight(path))
|
|
dom.on('scroll', () => highlight(path))
|
|
dom.on(sidebar, 'mouseover', () => {
|
|
hoverOver = true
|
|
})
|
|
dom.on(sidebar, 'mouseleave', () => {
|
|
hoverOver = false
|
|
})
|
|
}
|
|
|
|
export function scrollIntoView(path, id) {
|
|
if (!id) {
|
|
return
|
|
}
|
|
|
|
const section = dom.find('#' + cssEscape(id))
|
|
section && scrollTo(section)
|
|
|
|
const li = nav[getNavKey(path, id)]
|
|
const sidebar = dom.getNode('.sidebar')
|
|
const active = dom.find(sidebar, 'li.active')
|
|
active && active.classList.remove('active')
|
|
li && li.classList.add('active')
|
|
}
|
|
|
|
const scrollEl = dom.$.scrollingElement || dom.$.documentElement
|
|
|
|
export function scroll2Top(offset = 0) {
|
|
scrollEl.scrollTop = offset === true ? 0 : Number(offset)
|
|
}
|