mirror of
https://github.com/nagisa77/OpenIsle.git
synced 2026-06-09 03:27:32 +08:00
Merge pull request #394 from nagisa77/codex/fix-sticky-header-and-jumptohashcomment
fix: sticky scroller and hash comment navigation
This commit is contained in:
@@ -56,7 +56,8 @@ body {
|
|||||||
font-family: 'Roboto', sans-serif;
|
font-family: 'Roboto', sans-serif;
|
||||||
background-color: var(--normal-background-color);
|
background-color: var(--normal-background-color);
|
||||||
color: var(--text-color);
|
color: var(--text-color);
|
||||||
/* overflow: hidden; 禁止滚动 */
|
/* 禁止滚动 */
|
||||||
|
/* overflow: hidden; */
|
||||||
}
|
}
|
||||||
|
|
||||||
/*************************
|
/*************************
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<div v-if="isWaitingFetchingPost" class="loading-container">
|
<div v-if="isWaitingFetchingPost" class="loading-container">
|
||||||
<l-hatch size="28" stroke="4" speed="3.5" color="var(--primary-color)"></l-hatch>
|
<l-hatch size="28" stroke="4" speed="3.5" color="var(--primary-color)"></l-hatch>
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="post-page-main-container" ref="mainContainer" @scroll="onScroll">
|
<div v-else class="post-page-main-container" ref="mainContainer">
|
||||||
<div class="article-title-container">
|
<div class="article-title-container">
|
||||||
<div class="article-title-container-left">
|
<div class="article-title-container-left">
|
||||||
<div class="article-title">{{ title }}</div>
|
<div class="article-title">{{ title }}</div>
|
||||||
@@ -156,6 +156,7 @@ export default {
|
|||||||
const defaultTitle = document.title
|
const defaultTitle = document.title
|
||||||
const metaDescriptionEl = document.querySelector('meta[name="description"]')
|
const metaDescriptionEl = document.querySelector('meta[name="description"]')
|
||||||
const defaultDescription = metaDescriptionEl ? metaDescriptionEl.getAttribute('content') : ''
|
const defaultDescription = metaDescriptionEl ? metaDescriptionEl.getAttribute('content') : ''
|
||||||
|
const headerHeight = parseFloat(getComputedStyle(document.documentElement).getPropertyValue('--header-height')) || 0
|
||||||
|
|
||||||
watch(title, t => {
|
watch(title, t => {
|
||||||
document.title = `OpenIsle - ${t}`
|
document.title = `OpenIsle - ${t}`
|
||||||
@@ -170,6 +171,7 @@ export default {
|
|||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
document.title = defaultTitle
|
document.title = defaultTitle
|
||||||
if (metaDescriptionEl) metaDescriptionEl.setAttribute('content', defaultDescription)
|
if (metaDescriptionEl) metaDescriptionEl.setAttribute('content', defaultDescription)
|
||||||
|
window.removeEventListener('scroll', updateCurrentIndex)
|
||||||
})
|
})
|
||||||
|
|
||||||
const lightboxVisible = ref(false)
|
const lightboxVisible = ref(false)
|
||||||
@@ -202,12 +204,12 @@ export default {
|
|||||||
const items = []
|
const items = []
|
||||||
if (mainContainer.value) {
|
if (mainContainer.value) {
|
||||||
const main = mainContainer.value.querySelector('.info-content-container')
|
const main = mainContainer.value.querySelector('.info-content-container')
|
||||||
if (main) items.push({ el: main, top: 0 })
|
if (main) items.push({ el: main, top: getTop(main) })
|
||||||
|
|
||||||
for (const c of comments.value) {
|
for (const c of comments.value) {
|
||||||
const el = document.getElementById('comment-' + c.id)
|
const el = document.getElementById('comment-' + c.id)
|
||||||
if (el) {
|
if (el) {
|
||||||
items.push({ el, top: getTopRelativeTo(el, mainContainer.value) })
|
items.push({ el, top: getTop(el) })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 根据 top 排序,防止评论异步插入后顺序错乱
|
// 根据 top 排序,防止评论异步插入后顺序错乱
|
||||||
@@ -230,11 +232,8 @@ export default {
|
|||||||
parentUserName: parentUserName
|
parentUserName: parentUserName
|
||||||
})
|
})
|
||||||
|
|
||||||
const getTopRelativeTo = (el, container) => {
|
const getTop = (el) => {
|
||||||
const elRect = el.getBoundingClientRect()
|
return el.getBoundingClientRect().top + window.scrollY
|
||||||
const parentRect = container.getBoundingClientRect()
|
|
||||||
// 加上 scrollTop,得到相对于 container 内部顶部的距离
|
|
||||||
return elRect.top - parentRect.top + container.scrollTop
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const findCommentPath = (id, list) => {
|
const findCommentPath = (id, list) => {
|
||||||
@@ -336,19 +335,16 @@ export default {
|
|||||||
async () => {
|
async () => {
|
||||||
await nextTick()
|
await nextTick()
|
||||||
gatherPostItems()
|
gatherPostItems()
|
||||||
|
updateCurrentIndex()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
const updateCurrentIndex = () => {
|
const updateCurrentIndex = () => {
|
||||||
const container = mainContainer.value
|
const scrollTop = window.scrollY
|
||||||
if (!container) return
|
|
||||||
|
|
||||||
const scrollTop = container.scrollTop
|
|
||||||
|
|
||||||
for (let i = 0; i < postItems.value.length; i++) {
|
for (let i = 0; i < postItems.value.length; i++) {
|
||||||
const el = postItems.value[i]
|
const el = postItems.value[i]
|
||||||
// 计算元素相对 container 顶部的 top
|
const top = getTop(el)
|
||||||
const top = getTopRelativeTo(el, container)
|
|
||||||
const bottom = top + el.offsetHeight
|
const bottom = top + el.offsetHeight
|
||||||
|
|
||||||
if (bottom > scrollTop) {
|
if (bottom > scrollTop) {
|
||||||
@@ -362,9 +358,9 @@ export default {
|
|||||||
const index = Number(e.target.value)
|
const index = Number(e.target.value)
|
||||||
currentIndex.value = index
|
currentIndex.value = index
|
||||||
const target = postItems.value[index - 1]
|
const target = postItems.value[index - 1]
|
||||||
if (target && mainContainer.value) {
|
if (target) {
|
||||||
const top = getTopRelativeTo(target, mainContainer.value)
|
const top = getTop(target) - headerHeight - 20 // 20 for beauty
|
||||||
mainContainer.value.scrollTo({ top, behavior: 'instant' })
|
window.scrollTo({ top, behavior: 'auto' })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -572,10 +568,11 @@ export default {
|
|||||||
const id = hash.substring('#comment-'.length)
|
const id = hash.substring('#comment-'.length)
|
||||||
await nextTick()
|
await nextTick()
|
||||||
const el = document.getElementById('comment-' + id)
|
const el = document.getElementById('comment-' + id)
|
||||||
if (el && mainContainer.value) {
|
if (el) {
|
||||||
mainContainer.value.scrollTo({ top: getTopRelativeTo(el, mainContainer.value), behavior: 'instant' })
|
const top = el.getBoundingClientRect().top + window.scrollY - headerHeight - 20 // 20 for beauty
|
||||||
|
window.scrollTo({ top, behavior: 'smooth' })
|
||||||
el.classList.add('comment-highlight')
|
el.classList.add('comment-highlight')
|
||||||
setTimeout(() => el.classList.remove('comment-highlight'), 2000)
|
setTimeout(() => el.classList.remove('comment-highlight'), 4000)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -590,6 +587,7 @@ export default {
|
|||||||
await fetchPost()
|
await fetchPost()
|
||||||
if (id) expandCommentPath(id)
|
if (id) expandCommentPath(id)
|
||||||
updateCurrentIndex()
|
updateCurrentIndex()
|
||||||
|
window.addEventListener('scroll', updateCurrentIndex)
|
||||||
await jumpToHashComment()
|
await jumpToHashComment()
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -612,7 +610,6 @@ export default {
|
|||||||
postId,
|
postId,
|
||||||
postComment,
|
postComment,
|
||||||
onSliderInput,
|
onSliderInput,
|
||||||
onScroll: updateCurrentIndex,
|
|
||||||
copyPostLink,
|
copyPostLink,
|
||||||
subscribePost,
|
subscribePost,
|
||||||
unsubscribePost,
|
unsubscribePost,
|
||||||
@@ -671,6 +668,9 @@ export default {
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
width: 15%;
|
width: 15%;
|
||||||
|
position: sticky;
|
||||||
|
top: var(--header-height);
|
||||||
|
align-self: flex-start;
|
||||||
}
|
}
|
||||||
|
|
||||||
.comment-config-container {
|
.comment-config-container {
|
||||||
|
|||||||
Reference in New Issue
Block a user