diff --git a/pages/index/home.vue b/pages/index/home.vue index 25e342d..6f40f53 100644 --- a/pages/index/home.vue +++ b/pages/index/home.vue @@ -41,17 +41,23 @@ - + @@ -232,11 +238,66 @@ export default { ], - currentVideo: '' + currentVideo: '', + + // 设备类型检测 + isTablet: false + } + }, + + computed: { + // 轮播图配置 + swiperConfig() { + if (this.isTablet) { + // 平板设备使用卡片式轮播 + return { + height: "200", + radius: "16", + previousMargin: "60", + nextMargin: "60", + displayMultipleItems: 1.5 + } + } else { + // 手机设备使用普通轮播 + return { + height: "121", + radius: "12", + previousMargin: "0", + nextMargin: "0", + displayMultipleItems: 1 + } + } } }, methods: { + // 检测设备类型 + detectDevice() { + // #ifdef H5 + const userAgent = navigator.userAgent + const screenWidth = window.innerWidth || document.documentElement.clientWidth + const screenHeight = window.innerHeight || document.documentElement.clientHeight + + // 判断是否为平板设备 + // 1. 屏幕宽度大于768px + // 2. 或者是iPad设备 + this.isTablet = screenWidth >= 768 || /iPad|Android.*(?=.*\b(tablet|pad)\b)/i.test(userAgent) + + console.log('设备检测结果:', { + screenWidth, + screenHeight, + userAgent, + isTablet: this.isTablet + }) + // #endif + + // #ifndef H5 + // 非H5环境,通过系统信息判断 + const systemInfo = uni.getSystemInfoSync() + const screenWidth = systemInfo.screenWidth + this.isTablet = screenWidth >= 768 + // #endif + }, // 開動頁面關閉處理 onSplashClose() { console.log('開動頁面已關閉') @@ -420,11 +481,31 @@ export default { }, async onShow() { + // 检测设备类型 + this.detectDevice() + // 先获取基础数据 await Promise.all([this.getBanner(), this.getSignup(), this.getCategory(), this.getLabel()]) // 根据label数据获取对应的书籍 await this.getBooksByLabels() + }, + + mounted() { + // 页面挂载时也检测一次设备类型 + this.detectDevice() + + // #ifdef H5 + // 监听窗口大小变化 + window.addEventListener('resize', this.detectDevice) + // #endif + }, + + beforeDestroy() { + // #ifdef H5 + // 移除事件监听 + window.removeEventListener('resize', this.detectDevice) + // #endif } } @@ -499,6 +580,38 @@ export default { margin: 20rpx; border-radius: 12rpx; overflow: hidden; + + // 平板设备的轮播图样式 + &.tablet-swiper { + margin: 30rpx 0; + border-radius: 16rpx; + + // 卡片式轮播的额外样式 + :deep(.uv-swiper) { + .swiper-slide { + transition: all 0.3s ease; + transform-origin: center; + + // 非激活状态的卡片 + &:not(.swiper-slide-active) { + transform: scale(0.9); + opacity: 0.7; + } + + // 激活状态的卡片 + &.swiper-slide-active { + transform: scale(1); + opacity: 1; + z-index: 2; + } + } + + // 调整指示器位置 + .uv-swiper__indicator { + bottom: -40rpx; + } + } + } } // 内容区块 diff --git a/subPages/home/book.vue b/subPages/home/book.vue index 0b8b5b6..473d00b 100644 --- a/subPages/home/book.vue +++ b/subPages/home/book.vue @@ -35,6 +35,9 @@ style="height: 100vh;" class="scroll-container" @scroll="onScroll" + @touchstart="onTouchStart" + @touchmove="onTouchMove" + @touchend="onTouchEnd" > {{ currentPageTitle }} @@ -54,7 +57,7 @@ - + {{ token.text }} - + 10) { + // 如果当前正在自动滚动,立即停止 + if (this.isScrolling) { + console.log('🛑 检测到用户手动滚动,停止自动滚动'); + this.isScrolling = false; + + // 清除滚动防抖定时器 + if (this.scrollDebounceTimer) { + clearTimeout(this.scrollDebounceTimer); + this.scrollDebounceTimer = null; + } + } + } + }, + + // 触摸结束事件 - 用户停止触摸 + onTouchEnd(e) { + this.isUserTouching = false; + + // 设置一个短暂的延迟,在用户停止触摸后的一段时间内仍然阻止自动滚动 + // 这样可以避免用户刚停止滚动就立即触发自动滚动 + this.userScrollTimer = setTimeout(() => { + console.log('✋ 用户滚动操作结束,允许自动滚动'); + this.userScrollTimer = null; + }, 1000); // 1秒后允许自动滚动 + + console.log('👆 用户停止触摸屏幕'); + }, + + // 检查是否应该阻止自动滚动 + shouldPreventAutoScroll() { + return this.isUserTouching || this.userScrollTimer !== null; + }, + // 处理scroll-view滚动事件 onScroll(e) { // 更新当前页面的滚动位置 const scrollTop = e.detail.scrollTop; const currentPageIndex = this.currentPage - 1; + const previousScrollTop = this.scrollTops[currentPageIndex] || 0; // 只有当滚动位置发生显著变化时才更新 - if (Math.abs((this.scrollTops[currentPageIndex] || 0) - scrollTop) > 5) { + if (Math.abs(previousScrollTop - scrollTop) > 5) { + // 检测是否为手动滚动(如果正在自动滚动中,但滚动位置与预期不符,则认为是手动滚动) + if (this.isScrolling) { + // 如果滚动差异很大,可能是用户手动滚动,中断自动滚动状态 + const scrollDifference = Math.abs(previousScrollTop - scrollTop); + if (scrollDifference > 100) { // 大幅度滚动,很可能是手动操作 + console.log('🖐️ 检测到手动滚动,中断自动滚动状态'); + this.isScrolling = false; + } + } + this.$set(this.scrollTops, currentPageIndex, scrollTop); } }, @@ -677,20 +754,52 @@ export default { // 处理滚动到高亮文本 onScrollToText(scrollData) { + // 检查是否应该阻止自动滚动(用户正在手动操作) + if (this.shouldPreventAutoScroll()) { + console.log('🚫 用户正在手动滚动,跳过自动滚动到文本'); + return; + } + // 防抖处理:如果正在滚动中,清除之前的定时器 if (this.scrollDebounceTimer) { clearTimeout(this.scrollDebounceTimer); } this.scrollDebounceTimer = setTimeout(() => { + // 再次检查是否应该阻止自动滚动 + if (this.shouldPreventAutoScroll()) { + console.log('🚫 防抖延迟后检测到用户手动滚动,跳过自动滚动到文本'); + return; + } this.performScrollToText(scrollData); }, 100); // 100ms防抖延迟 }, // 执行滚动到高亮文本的具体逻辑 performScrollToText(scrollData) { + // 最终检查:如果用户正在手动操作,直接返回 + if (this.shouldPreventAutoScroll()) { + console.log('🚫 执行滚动前检测到用户手动操作,取消自动滚动'); + return; + } + + // 确保在任何情况下都能重置滚动状态 + const resetScrollingState = () => { + this.isScrolling = false; + console.log('🔄 滚动状态已重置'); + }; + + // 设置安全超时,确保状态不会永久卡住 + const safetyTimeout = setTimeout(() => { + if (this.isScrolling) { + console.warn('⚠️ 滚动状态安全超时,强制重置'); + resetScrollingState(); + } + }, 2000); // 2秒安全超时 + if (!scrollData || typeof scrollData.highlightIndex !== 'number' || scrollData.highlightIndex < 0) { console.warn('滚动数据无效:', scrollData); + clearTimeout(safetyTimeout); return; } @@ -700,12 +809,14 @@ export default { scrollDataPage: scrollData.currentPage, currentPage: this.currentPage }); + clearTimeout(safetyTimeout); return; } // 如果正在滚动中,跳过本次滚动 if (this.isScrolling) { console.warn('正在滚动中,跳过本次滚动'); + clearTimeout(safetyTimeout); return; } @@ -742,6 +853,9 @@ export default { query.select(selector).boundingClientRect(); query.exec((res) => { + // 清除安全超时 + clearTimeout(safetyTimeout); + const scrollViewRect = res[0]; const targetRect = res[1]; @@ -772,7 +886,7 @@ export default { // 滚动完成后重置状态 setTimeout(() => { - this.isScrolling = false; + resetScrollingState(); }, 300); // 稍微减少等待时间 console.log('✅ 滚动到高亮文本:', { @@ -784,7 +898,7 @@ export default { }); } else { // 不需要滚动,立即重置状态 - this.isScrolling = false; + resetScrollingState(); console.log('📍 目标已在视野内,无需滚动'); } } else { @@ -795,7 +909,6 @@ export default { currentPage: this.currentPage, highlightIndex: scrollData.highlightIndex }); - this.isScrolling = false; // 尝试备用方案:直接滚动到页面顶部附近 if (!targetRect) { @@ -803,8 +916,11 @@ export default { const fallbackScrollTop = scrollData.highlightIndex * 100; // 简单估算位置 this.$set(this.scrollTops, this.currentPage - 1, fallbackScrollTop); setTimeout(() => { - this.isScrolling = false; + resetScrollingState(); }, 300); + } else { + // 立即重置状态 + resetScrollingState(); } } }); @@ -1404,6 +1520,24 @@ export default { return false; }, + // 判断划线重点卡片中的文本是否应该高亮 + isCardTextHighlighted(page, index) { + // 只有当前页面且是文本类型才可能高亮 + if (page !== this.bookPages[this.currentPage - 1]) return false; + + // 计算当前页面中text类型元素的索引 + let textIndex = 0; + for (let i = 0; i <= index; i++) { + if (page[i].type === 'text') { + if (i === index) { + return textIndex === this.currentHighlightIndex; + } + textIndex++; + } + } + return false; + }, + async previousPage() { if (this.currentPage > 1) { this.currentPage--; @@ -2175,6 +2309,9 @@ export default { border: 1px solid #ffe58f; border-radius: 8px; padding: 10rpx 20rpx; + + /* 添加平滑过渡动画 */ + transition: all 0.3s ease; } .text-highlight { @@ -2182,15 +2319,10 @@ export default { border-left: 4rpx solid #ffd700; /* 左侧金色边框作为朗读指示 */ padding: 4rpx 8rpx; border-radius: 6rpx; - transition: all 0.3s ease; box-shadow: 0 2rpx 6rpx rgba(255, 215, 0, 0.15); /* 柔和的阴影 */ + + /* 添加平滑过渡动画 */ + transition: all 0.3s ease; } - - - - - - -