From 4c0d69e1b2a90bc6eec3e0752632595350ee95ee Mon Sep 17 00:00:00 2001 From: imeepos Date: Wed, 3 Sep 2025 20:39:18 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E4=BF=AE=E5=A4=8D=E9=A6=96=E9=A1=B5?= =?UTF-8?q?=E6=BB=9A=E5=8A=A8=E5=8D=A1=E9=A1=BF=E5=B9=B6=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E4=B8=8B=E6=8B=89=E5=88=B7=E6=96=B0=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 滚动性能优化: - 使用ScrollView组件替代普通View,提供原生滚动性能 - 启用硬件加速:transform: translateZ(0)和will-change属性 - 优化CSS动画:减少clip-path动画频率,简化transition效果 - 图片渲染优化:image-rendering: optimizeSpeed和backface-visibility 下拉刷新功能: - 集成ScrollView原生下拉刷新能力 - 添加refresherEnabled、refresherTriggered等配置 - 实现handleRefresh异步刷新逻辑 - 完善错误处理和用户反馈 性能提升措施: - 移除不必要的transition动画减少重绘 - 使用requestAnimationFrame节流触摸事件 - 启用contain: layout style paint优化渲染 - 简化active状态效果,使用opacity替代transform 用户体验改进: - 流畅的原生滚动体验,消除卡顿现象 - 直观的下拉刷新操作,符合用户习惯 - 完整的加载状态和错误提示 - 自动数据同步和状态管理 技术实现: - ScrollView enhanced模式启用增强特性 - enablePassive被动事件监听提升性能 - refresherBackground和refresherDefaultStyle视觉定制 - 异步错误处理和Toast提示集成 解决问题:首页滚动时的卡顿现象,提升用户交互体验 --- src/components/TemplateCard/index.css | 20 ++++++-- src/components/TemplateCard/index.tsx | 13 ++++-- src/pages/home/index.css | 17 ++++++- src/pages/home/index.tsx | 66 ++++++++++++++++++++++----- 4 files changed, 93 insertions(+), 23 deletions(-) diff --git a/src/components/TemplateCard/index.css b/src/components/TemplateCard/index.css index a5f0401..eaca306 100644 --- a/src/components/TemplateCard/index.css +++ b/src/components/TemplateCard/index.css @@ -3,7 +3,7 @@ border-radius: 16px; padding: 0; box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08); - transition: all 0.3s ease; + /* 优化:移除transition,减少重绘 */ cursor: pointer; display: flex; flex-direction: column; @@ -12,11 +12,14 @@ break-inside: avoid; width: 100%; box-sizing: border-box; + /* 性能优化:启用硬件加速 */ + transform: translateZ(0); + will-change: transform; } +/* 优化:简化active状态,减少重绘 */ .template-card:active { - transform: translateY(-2px); - box-shadow: 0 8px 30px rgba(0, 0, 0, 0.15); + opacity: 0.9; } /* 合成对比图片区域 */ @@ -46,8 +49,12 @@ min-height: 240px; } +/* 优化:减少clip-path动画频率,提升性能 */ .overlay-layer { - transition: clip-path 0.1s ease-out; + transition: clip-path 0.2s ease-out; + /* 启用硬件加速 */ + transform: translateZ(0); + will-change: clip-path; } .full-image { @@ -56,6 +63,11 @@ min-height: 240px; object-fit: cover; display: block; + /* 性能优化:启用硬件加速和图片优化 */ + transform: translateZ(0); + image-rendering: optimizeSpeed; + /* 防止图片闪烁 */ + backface-visibility: hidden; } diff --git a/src/components/TemplateCard/index.tsx b/src/components/TemplateCard/index.tsx index fa9d13e..8ac7c96 100644 --- a/src/components/TemplateCard/index.tsx +++ b/src/components/TemplateCard/index.tsx @@ -43,7 +43,7 @@ export default function TemplateCard({ template, onClick }: TemplateCardProps) { await getContainerInfo() } - // 处理触摸移动 + // 处理触摸移动 - 优化:添加节流,减少计算频率 const handleTouchMove = (e: any) => { if (!isDragging || !containerInfo) return e.stopPropagation() @@ -51,11 +51,14 @@ export default function TemplateCard({ template, onClick }: TemplateCardProps) { const touch = e.touches[0] if (!touch) return - // 计算触摸点相对于容器的位置 - const touchX = touch.clientX - containerInfo.left - const percentage = Math.max(10, Math.min(90, (touchX / containerInfo.width) * 100)) + // 使用requestAnimationFrame节流,提升性能 + requestAnimationFrame(() => { + // 计算触摸点相对于容器的位置 + const touchX = touch.clientX - containerInfo.left + const percentage = Math.max(10, Math.min(90, (touchX / containerInfo.width) * 100)) - setSplitPosition(percentage) + setSplitPosition(percentage) + }) } // 处理触摸结束 diff --git a/src/pages/home/index.css b/src/pages/home/index.css index 792ea68..066a25d 100644 --- a/src/pages/home/index.css +++ b/src/pages/home/index.css @@ -1,7 +1,18 @@ .home { - padding: 16px 12px 20px; background: linear-gradient(180deg, #f8f9fa 0%, #e9ecef 100%); - min-height: 100vh; + height: 100vh; + display: flex; + flex-direction: column; +} + +/* ScrollView 容器样式 */ +.home-scroll { + flex: 1; + height: 100%; + padding: 16px 12px 20px; + /* 滚动性能优化 */ + -webkit-overflow-scrolling: touch; + overflow-scrolling: touch; } .home-header { @@ -37,6 +48,8 @@ max-width: 100%; margin: 0 auto; padding: 0 4px; + /* 最小高度确保内容撑开 */ + min-height: 100%; } /* 响应式调整 */ diff --git a/src/pages/home/index.tsx b/src/pages/home/index.tsx index ccb9afc..4689095 100644 --- a/src/pages/home/index.tsx +++ b/src/pages/home/index.tsx @@ -1,4 +1,4 @@ -import { View, Text } from '@tarojs/components' +import { View, Text, ScrollView } from '@tarojs/components' import { useEffect, useState } from 'react' import Taro, { navigateTo } from '@tarojs/taro' import { useAppDispatch, useAppSelector } from '../../hooks/redux' @@ -16,10 +16,37 @@ export default function Home() { const sdk = useSdk() const serverSdk = useServerSdk() const [loading, setLoading] = useState(false) + const [refreshing, setRefreshing] = useState(false) const loadTemplates = async () => { - const templates = await serverSdk.getAllTemplates() - dispatch(initTemplates(templates)) + try { + const templates = await serverSdk.getAllTemplates() + dispatch(initTemplates(templates)) + } catch (error) { + console.error('加载模板失败:', error) + Taro.showToast({ + title: '加载模板失败', + icon: 'error', + duration: 2000 + }) + } + } + + // 下拉刷新处理 + const handleRefresh = async () => { + setRefreshing(true) + try { + await loadTemplates() + Taro.showToast({ + title: '刷新成功', + icon: 'success', + duration: 1500 + }) + } catch (error) { + console.error('刷新失败:', error) + } finally { + setRefreshing(false) + } } useEffect(() => { @@ -103,15 +130,30 @@ export default function Home() { return ( - - {templates.map((template) => ( - - ))} - + + + {templates.map((template) => ( + + ))} + + ) } \ No newline at end of file