word 搜索优化

This commit is contained in:
cwchen 2025-11-12 15:49:02 +08:00
parent d6bac94fda
commit 5b7c792ab4
1 changed files with 84 additions and 20 deletions

View File

@ -65,6 +65,7 @@ export default {
searchSegments: [],
docRendered: false,
abortController: null,
scrollAnimationFrame: null,
}
},
mounted() {
@ -75,6 +76,7 @@ export default {
},
beforeDestroy() {
this.cancelFetch()
this.cancelScrollAnimation()
},
watch: {
'$route.query.url'(newUrl, oldUrl) {
@ -403,7 +405,7 @@ export default {
this.currentResultIndex = 0
this.updateActiveHighlight()
this.$nextTick(() => {
this.navigateToResult(this.currentResultIndex)
this.navigateToResult(this.currentResultIndex, false)
})
},
@ -463,7 +465,53 @@ export default {
return offset
},
navigateToResult(index, useSmoothScroll = false) {
cancelScrollAnimation() {
if (this.scrollAnimationFrame) {
cancelAnimationFrame(this.scrollAnimationFrame)
this.scrollAnimationFrame = null
}
},
smoothScrollTo(container, target, baseDuration = 300) {
if (!container) return
const maxScroll = container.scrollHeight - container.clientHeight
const finalTarget = Math.min(Math.max(target, 0), Math.max(maxScroll, 0))
const start = container.scrollTop
const change = finalTarget - start
if (Math.abs(change) < 1) {
container.scrollTop = finalTarget
return
}
const distanceFactor = Math.min(Math.abs(change) / Math.max(container.clientHeight, 1), 2.4)
const duration = Math.min(600, baseDuration + distanceFactor * 120)
const startTime = performance.now()
const ease = (t) => 1 - Math.pow(1 - t, 3)
const velocityBoost = Math.min(Math.max(Math.abs(change) / 2400, 0), 0.25)
this.cancelScrollAnimation()
const step = (now) => {
const elapsed = now - startTime
const progress = Math.min(elapsed / duration, 1)
const eased = ease(progress)
const basePosition = start + change * eased
const overshoot = velocityBoost * Math.sin(eased * Math.PI)
container.scrollTop = Math.min(Math.max(basePosition + overshoot * change, 0), maxScroll)
if (progress < 1) {
this.scrollAnimationFrame = requestAnimationFrame(step)
} else {
container.scrollTop = finalTarget
this.scrollAnimationFrame = null
}
}
this.scrollAnimationFrame = requestAnimationFrame(step)
},
navigateToResult(index, useSmoothScroll = true) {
if (!this.searchResults.length || index < 0 || index >= this.searchResults.length) return
this.currentResultIndex = index
this.updateActiveHighlight()
@ -485,28 +533,44 @@ export default {
return
}
try {
const wrapperRect = wrapper.getBoundingClientRect()
const currentScrollTop = wrapper.scrollTop
const targetTopRelativeToWrapper = targetRect.top - wrapperRect.top + currentScrollTop
const margin = 24
const desiredScrollTop = Math.max(targetTopRelativeToWrapper - margin, 0)
wrapper.scrollTop = desiredScrollTop
} catch (error) {
const performScroll = () => {
try {
let absoluteTop = 0
let node = target
while (node && node !== wrapper) {
absoluteTop += node.offsetTop || 0
node = node.offsetParent
}
const wrapperRect = wrapper.getBoundingClientRect()
const currentScrollTop = wrapper.scrollTop
const targetTopRelativeToWrapper = targetRect.top - wrapperRect.top + currentScrollTop
const margin = 24
wrapper.scrollTop = Math.max(absoluteTop - margin, 0)
} catch (e) {
console.error('Scroll error:', e)
const desiredScrollTop = Math.max(targetTopRelativeToWrapper - margin, 0)
if (useSmoothScroll) {
this.smoothScrollTo(wrapper, desiredScrollTop)
} else {
this.cancelScrollAnimation()
wrapper.scrollTop = desiredScrollTop
}
} catch (error) {
try {
let absoluteTop = 0
let node = target
while (node && node !== wrapper) {
absoluteTop += node.offsetTop || 0
node = node.offsetParent
}
const margin = 24
const desiredScrollTop = Math.max(absoluteTop - margin, 0)
if (useSmoothScroll) {
this.smoothScrollTo(wrapper, desiredScrollTop)
} else {
this.cancelScrollAnimation()
wrapper.scrollTop = desiredScrollTop
}
} catch (e) {
console.error('Scroll error:', e)
}
}
}
performScroll()
})
})
})