word 搜索优化
This commit is contained in:
parent
d6bac94fda
commit
5b7c792ab4
|
|
@ -65,6 +65,7 @@ export default {
|
||||||
searchSegments: [],
|
searchSegments: [],
|
||||||
docRendered: false,
|
docRendered: false,
|
||||||
abortController: null,
|
abortController: null,
|
||||||
|
scrollAnimationFrame: null,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
|
|
@ -75,6 +76,7 @@ export default {
|
||||||
},
|
},
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
this.cancelFetch()
|
this.cancelFetch()
|
||||||
|
this.cancelScrollAnimation()
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
'$route.query.url'(newUrl, oldUrl) {
|
'$route.query.url'(newUrl, oldUrl) {
|
||||||
|
|
@ -403,7 +405,7 @@ export default {
|
||||||
this.currentResultIndex = 0
|
this.currentResultIndex = 0
|
||||||
this.updateActiveHighlight()
|
this.updateActiveHighlight()
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
this.navigateToResult(this.currentResultIndex)
|
this.navigateToResult(this.currentResultIndex, false)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -463,7 +465,53 @@ export default {
|
||||||
return offset
|
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
|
if (!this.searchResults.length || index < 0 || index >= this.searchResults.length) return
|
||||||
this.currentResultIndex = index
|
this.currentResultIndex = index
|
||||||
this.updateActiveHighlight()
|
this.updateActiveHighlight()
|
||||||
|
|
@ -485,6 +533,7 @@ export default {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const performScroll = () => {
|
||||||
try {
|
try {
|
||||||
const wrapperRect = wrapper.getBoundingClientRect()
|
const wrapperRect = wrapper.getBoundingClientRect()
|
||||||
const currentScrollTop = wrapper.scrollTop
|
const currentScrollTop = wrapper.scrollTop
|
||||||
|
|
@ -492,7 +541,12 @@ export default {
|
||||||
const margin = 24
|
const margin = 24
|
||||||
const desiredScrollTop = Math.max(targetTopRelativeToWrapper - margin, 0)
|
const desiredScrollTop = Math.max(targetTopRelativeToWrapper - margin, 0)
|
||||||
|
|
||||||
|
if (useSmoothScroll) {
|
||||||
|
this.smoothScrollTo(wrapper, desiredScrollTop)
|
||||||
|
} else {
|
||||||
|
this.cancelScrollAnimation()
|
||||||
wrapper.scrollTop = desiredScrollTop
|
wrapper.scrollTop = desiredScrollTop
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
try {
|
try {
|
||||||
let absoluteTop = 0
|
let absoluteTop = 0
|
||||||
|
|
@ -502,11 +556,21 @@ export default {
|
||||||
node = node.offsetParent
|
node = node.offsetParent
|
||||||
}
|
}
|
||||||
const margin = 24
|
const margin = 24
|
||||||
wrapper.scrollTop = Math.max(absoluteTop - margin, 0)
|
const desiredScrollTop = Math.max(absoluteTop - margin, 0)
|
||||||
|
|
||||||
|
if (useSmoothScroll) {
|
||||||
|
this.smoothScrollTo(wrapper, desiredScrollTop)
|
||||||
|
} else {
|
||||||
|
this.cancelScrollAnimation()
|
||||||
|
wrapper.scrollTop = desiredScrollTop
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('Scroll error:', e)
|
console.error('Scroll error:', e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
performScroll()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue