feat: 修复首页新闻中心卡片布局跳变问题
问题根源:
使用 useBreakpointValue 的 isMobile 变量在初始渲染时返回 undefined,导致:
1. 服务端渲染/首次加载时显示一种布局
2. 客户端水合后切换到另一种布局
3. 用户看到明显的布局跳变(先横向后纵向,或反之)
解决方案:
不使用条件渲染两套完全不同的 JSX,而是使用响应式样式让同一套 JSX 自动适应不同屏幕。
修改策略:
将移动端(VStack)和桌面端(Flex横向)合并为一套响应式布局:
- 使用 Flex + 响应式 flexDirection
- flexDirection={{ base: column, md: row }}(移动端纵向,桌面端横向)
- 统一使用响应式属性而不是条件渲染
This commit is contained in:
@@ -34,7 +34,6 @@ export default function HomePage() {
|
|||||||
const heroTextSize = useBreakpointValue({ base: 'md', md: 'lg', lg: 'xl' });
|
const heroTextSize = useBreakpointValue({ base: 'md', md: 'lg', lg: 'xl' });
|
||||||
const containerPx = useBreakpointValue({ base: 10, md: 10, lg: 10 });
|
const containerPx = useBreakpointValue({ base: 10, md: 10, lg: 10 });
|
||||||
const showDecorations = useBreakpointValue({ base: false, md: true });
|
const showDecorations = useBreakpointValue({ base: false, md: true });
|
||||||
const isMobile = useBreakpointValue({ base: true, md: false });
|
|
||||||
|
|
||||||
// 保留原有的调试信息
|
// 保留原有的调试信息
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -238,79 +237,49 @@ export default function HomePage() {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<CardBody p={{ base: 6, md: 8 }} position="relative" zIndex={1}>
|
<CardBody p={{ base: 6, md: 8 }} position="relative" zIndex={1}>
|
||||||
{isMobile ? (
|
{/* 响应式布局:移动端纵向,桌面端横向 */}
|
||||||
/* 移动端:垂直布局 */
|
<Flex
|
||||||
<VStack spacing={4} align="stretch">
|
direction={{ base: 'column', md: 'row' }}
|
||||||
<HStack spacing={4}>
|
align={{ base: 'stretch', md: 'center' }}
|
||||||
<Box
|
justify={{ base: 'flex-start', md: 'space-between' }}
|
||||||
p={3}
|
gap={{ base: 4, md: 6 }}
|
||||||
borderRadius="lg"
|
>
|
||||||
bg="yellow.400"
|
<Flex align="center" gap={{ base: 4, md: 6 }} flex={1}>
|
||||||
color="black"
|
<Box
|
||||||
>
|
p={{ base: 3, md: 4 }}
|
||||||
<Text fontSize="2xl">{coreFeatures[0].icon}</Text>
|
borderRadius={{ base: 'lg', md: 'xl' }}
|
||||||
</Box>
|
bg="yellow.400"
|
||||||
<VStack align="start" spacing={1} flex={1}>
|
color="black"
|
||||||
<Heading size="lg" color="white">
|
>
|
||||||
|
<Text fontSize={{ base: '2xl', md: '3xl' }}>{coreFeatures[0].icon}</Text>
|
||||||
|
</Box>
|
||||||
|
<VStack align="start" spacing={{ base: 1, md: 2 }} flex={1}>
|
||||||
|
<HStack>
|
||||||
|
<Heading size={{ base: 'lg', md: 'xl' }} color="white">
|
||||||
{coreFeatures[0].title}
|
{coreFeatures[0].title}
|
||||||
</Heading>
|
</Heading>
|
||||||
<Badge colorScheme="yellow" variant="solid" fontSize="xs">
|
<Badge colorScheme="yellow" variant="solid" fontSize={{ base: 'xs', md: 'sm' }}>
|
||||||
{coreFeatures[0].badge}
|
{coreFeatures[0].badge}
|
||||||
</Badge>
|
</Badge>
|
||||||
</VStack>
|
</HStack>
|
||||||
</HStack>
|
<Text color="whiteAlpha.800" fontSize={{ base: 'md', md: 'lg' }} maxW={{ md: 'md' }} lineHeight="tall">
|
||||||
<Text color="whiteAlpha.800" fontSize="md" lineHeight="tall">
|
{coreFeatures[0].description}
|
||||||
{coreFeatures[0].description}
|
</Text>
|
||||||
</Text>
|
</VStack>
|
||||||
<Button
|
|
||||||
colorScheme="yellow"
|
|
||||||
size="md"
|
|
||||||
borderRadius="full"
|
|
||||||
fontWeight="bold"
|
|
||||||
w="100%"
|
|
||||||
onClick={() => handleProductClick(coreFeatures[0].url)}
|
|
||||||
minH="44px"
|
|
||||||
>
|
|
||||||
进入功能 →
|
|
||||||
</Button>
|
|
||||||
</VStack>
|
|
||||||
) : (
|
|
||||||
/* 桌面端:横向布局 */
|
|
||||||
<Flex align="center" justify="space-between">
|
|
||||||
<HStack spacing={6}>
|
|
||||||
<Box
|
|
||||||
p={4}
|
|
||||||
borderRadius="xl"
|
|
||||||
bg="yellow.400"
|
|
||||||
color="black"
|
|
||||||
>
|
|
||||||
<Text fontSize="3xl">{coreFeatures[0].icon}</Text>
|
|
||||||
</Box>
|
|
||||||
<VStack align="start" spacing={2}>
|
|
||||||
<HStack>
|
|
||||||
<Heading size="xl" color="white">
|
|
||||||
{coreFeatures[0].title}
|
|
||||||
</Heading>
|
|
||||||
<Badge colorScheme="yellow" variant="solid" fontSize="sm">
|
|
||||||
{coreFeatures[0].badge}
|
|
||||||
</Badge>
|
|
||||||
</HStack>
|
|
||||||
<Text color="whiteAlpha.800" fontSize="lg" maxW="md">
|
|
||||||
{coreFeatures[0].description}
|
|
||||||
</Text>
|
|
||||||
</VStack>
|
|
||||||
</HStack>
|
|
||||||
<Button
|
|
||||||
colorScheme="yellow"
|
|
||||||
size="lg"
|
|
||||||
borderRadius="full"
|
|
||||||
fontWeight="bold"
|
|
||||||
onClick={() => handleProductClick(coreFeatures[0].url)}
|
|
||||||
>
|
|
||||||
进入功能 →
|
|
||||||
</Button>
|
|
||||||
</Flex>
|
</Flex>
|
||||||
)}
|
<Button
|
||||||
|
colorScheme="yellow"
|
||||||
|
size={{ base: 'md', md: 'lg' }}
|
||||||
|
borderRadius="full"
|
||||||
|
fontWeight="bold"
|
||||||
|
w={{ base: '100%', md: 'auto' }}
|
||||||
|
onClick={() => handleProductClick(coreFeatures[0].url)}
|
||||||
|
minH="44px"
|
||||||
|
flexShrink={0}
|
||||||
|
>
|
||||||
|
进入功能 →
|
||||||
|
</Button>
|
||||||
|
</Flex>
|
||||||
</CardBody>
|
</CardBody>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user