From fb7c04ce440fffaf62735728c40bc5fb49685480 Mon Sep 17 00:00:00 2001 From: huliyong <2783385703@qq.com> Date: Fri, 31 Oct 2025 01:48:48 +0800 Subject: [PATCH] =?UTF-8?q?fix(home/book):=20=E4=BC=98=E5=8C=96=E6=BB=9A?= =?UTF-8?q?=E5=8A=A8=E6=A3=80=E6=B5=8B=E9=98=88=E5=80=BC=E5=92=8C=E4=BD=8D?= =?UTF-8?q?=E7=BD=AE=E8=AE=A1=E7=AE=97=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 提高手动滚动检测阈值从50到80,减少误判 增加元素可视范围检查功能,优化滚动位置计算 统一精确滚动和普通滚动的阈值至30,减少不必要的微小滚动 --- subPages/home/book.vue | 95 +++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 82 insertions(+), 13 deletions(-) diff --git a/subPages/home/book.vue b/subPages/home/book.vue index c84626a..70ba6f3 100644 --- a/subPages/home/book.vue +++ b/subPages/home/book.vue @@ -373,9 +373,9 @@ export default { if (Math.abs(previousScrollTop - scrollTop) > 5) { // 检测是否为手动滚动(如果正在自动滚动中,但滚动位置与预期不符,则认为是手动滚动) if (this.isScrolling) { - // 如果滚动差异很大,可能是用户手动滚动,中断自动滚动状态 + // 提高手动滚动检测阈值,减少误判 const scrollDifference = Math.abs(previousScrollTop - scrollTop); - if (scrollDifference > 50) { // 调整阈值,避免误判 + if (scrollDifference > 80) { // 从50提高到80,减少误判 console.log('🖐️ 检测到手动滚动,中断自动滚动状态'); this.isScrolling = false; this.lastUserScrollTime = Date.now(); // 记录手动滚动时间 @@ -841,7 +841,8 @@ export default { const currentScroll = this.scrollTops[this.currentPage - 1] || 0; const scrollDifference = Math.abs(preciseScrollTop - currentScroll); - if (scrollDifference > 20) { + // 提高滚动阈值,减少不必要的微小滚动 + if (scrollDifference > 30) { // 从20提高到30 this.$set(this.scrollTops, this.currentPage - 1, preciseScrollTop); console.log('✅ 使用精确位置滚动:', { selector, @@ -856,7 +857,7 @@ export default { }, 200); } else { resetScrollingState(); - console.log('📍 目标已在视野内,无需滚动'); + console.log('📍 目标已在最佳可视位置,无需滚动'); } } else { // 精确计算失败,使用原有的查询方法作为备用 @@ -910,7 +911,8 @@ export default { const currentScroll = this.scrollTops[this.currentPage - 1] || 0; const scrollDifference = Math.abs(finalScrollTop - currentScroll); - if (scrollDifference > 20) { // 进一步降低滚动阈值,提高响应性 + // 提高滚动阈值,减少不必要的微小滚动 + if (scrollDifference > 30) { // 从20提高到30,与精确滚动保持一致 this.$set(this.scrollTops, this.currentPage - 1, finalScrollTop); // 滚动完成后重置状态 @@ -928,7 +930,7 @@ export default { } else { // 不需要滚动,立即重置状态 resetScrollingState(); - console.log('📍 目标已在视野内,无需滚动'); + console.log('📍 目标已在最佳可视位置,无需滚动'); } } else { console.error('❌ 未找到目标元素或scroll-view:', { @@ -1035,6 +1037,75 @@ export default { }); }, + // 检查元素是否在可视范围内 + isElementInViewport(elementPosition, currentScrollTop) { + const screenHeight = uni.getSystemInfoSync().windowHeight; + const viewportTop = currentScrollTop; + const viewportBottom = currentScrollTop + screenHeight; + + // 元素的顶部和底部位置 + const elementTop = elementPosition.top; + const elementBottom = elementPosition.bottom; + + // 检查元素是否完全或部分在可视范围内 + const isVisible = elementBottom > viewportTop && elementTop < viewportBottom; + + // 计算元素在可视范围内的比例 + const visibleTop = Math.max(elementTop, viewportTop); + const visibleBottom = Math.min(elementBottom, viewportBottom); + const visibleHeight = Math.max(0, visibleBottom - visibleTop); + const visibilityRatio = visibleHeight / elementPosition.height; + + return { + isVisible, + visibilityRatio, + elementTop, + elementBottom, + viewportTop, + viewportBottom + }; + }, + + // 计算最佳滚动位置 + calculateOptimalScrollPosition(targetElement, currentScrollTop) { + const screenHeight = uni.getSystemInfoSync().windowHeight; + + // 检查当前元素的可见性 + const visibility = this.isElementInViewport(targetElement, currentScrollTop); + + // 如果元素已经完全可见且在合适位置,不需要滚动 + if (visibility.isVisible && visibility.visibilityRatio > 0.8) { + // 检查元素是否在屏幕的合适位置(上方1/3到2/3之间) + const elementCenter = (targetElement.top + targetElement.bottom) / 2; + const relativePosition = (elementCenter - currentScrollTop) / screenHeight; + + if (relativePosition >= 0.2 && relativePosition <= 0.7) { + console.log('📍 元素已在最佳可视位置,无需滚动'); + return null; // 不需要滚动 + } + } + + // 计算目标滚动位置:让元素显示在屏幕上方1/3处(更舒适的阅读位置) + const optimalOffsetRatio = 0.3; // 30%的位置,比1/4更舒适 + const offsetFromTop = screenHeight * optimalOffsetRatio; + + // 考虑元素高度,确保不会被截断 + const elementHeight = targetElement.height; + const adjustedOffset = Math.min(offsetFromTop, screenHeight * 0.1); // 最小10%偏移 + + const targetScrollTop = Math.max(0, targetElement.top - adjustedOffset); + + console.log('🎯 计算最佳滚动位置:', { + currentVisibility: visibility, + elementHeight, + optimalOffsetRatio, + adjustedOffset, + targetScrollTop + }); + + return targetScrollTop; + }, + // 计算精确的滚动位置 async calculatePreciseScrollPosition(scrollData, elementPositions) { if (!elementPositions || elementPositions.length === 0) { @@ -1063,18 +1134,16 @@ export default { return null; } - // 计算滚动位置:让目标元素显示在屏幕上方1/4处 - const screenHeight = uni.getSystemInfoSync().windowHeight; - const offsetFromTop = screenHeight * 0.25; + // 获取当前滚动位置 + const currentScrollTop = this.scrollTops[this.currentPage - 1] || 0; - // 目标滚动位置 = 目标元素顶部位置 - 偏移量 - const targetScrollTop = Math.max(0, targetElement.top - offsetFromTop); + // 使用优化的滚动位置计算 + const targetScrollTop = this.calculateOptimalScrollPosition(targetElement, currentScrollTop); console.log('🎯 精确滚动位置计算:', { targetElementIndex, targetElement, - screenHeight, - offsetFromTop, + currentScrollTop, targetScrollTop });