word 搜索优化
This commit is contained in:
parent
d6bac94fda
commit
5b7c792ab4
|
|
@ -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()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
|||
Loading…
Reference in New Issue