Skip to Content
@anker-in/headless-ui 2.0 is released 🎉

ProductHero (产品Hero)

产品首屏展示组件,支持大图、标题、价格和购买按钮【✅ 已发布】

加载中...
当前视口: 1920px × 600px场景: 默认
打开链接

功能特性

ProductHero 是一个专为新品页面设计的英雄展示组件,用于在页面顶部突出展示产品核心信息和视觉。组件支持响应式布局、双图片适配、CTA 按钮集成等功能。

核心特性

  • 响应式布局 - 移动端垂直堆叠,平板及以上水平排列,自动适配不同屏幕尺寸
  • 双图片适配 - 桌面端和移动端独立图片资源,针对性优化显示效果
  • CTA 按钮集成 - 内置号召性用语按钮,支持自定义文本和链接
  • 主题支持 - light/dark 主题切换,通过 aiui-dark 类实现深色模式
  • BEM 命名规范 - 完整的 BEM 类名结构,便于样式定制和覆盖
  • 双副标题渲染 - 桌面端使用 Heading,移动端使用 Text,SEO 优化
  • 动态内容比例 - 内容区 36%-42%,图片区 58%-64%,响应式动态调整
  • 圆角卡片设计 - 图片使用 rounded-box 样式,符合现代设计风格
  • 曝光埋点集成 - 自动上报 useExposure 分析数据,追踪组件曝光
  • Ref 转发支持 - 支持父组件获取 DOM 引用,便于集成和控制

适用场景

  • 新品发布页顶部 - 突出展示新产品的核心卖点和视觉形象
  • 促销活动页 - 强调限时优惠或特殊活动信息
  • 产品详情页英雄区 - 作为产品详情页的首屏展示
  • 品牌展示页 - 展示品牌形象和核心价值主张
  • Landing Page - 落地页的首屏吸引用户注意力

Props 参数

ProductHeroProps

组件的顶层 Props 接口。

参数类型默认值必需说明
dataProductHeroData-产品英雄数据对象,包含所有展示内容
classNamestring--自定义 CSS 类名,追加到根容器 <section> 元素

ProductHeroData

产品英雄的数据结构,定义所有展示内容。

字段类型默认值必需说明
titlestring-主标题文本,通常为产品名称或核心卖点
subtitlestring-副标题/产品描述文本,提供更多产品信息
ctaTextstring-CTA 按钮文本,如 “Shop Now”, “Learn More”
ctaLinkstring-CTA 按钮跳转链接,支持相对路径和绝对路径
posterMedia-桌面端产品图片对象 ({ url, alt, thumbnailURL?, mimeType? })
mobPosterMedia-移动端产品图片对象 (在 <768px 断点显示)
modelSrcstring--3D 模型源 (可选,当前版本暂未使用,预留字段)
theme'light' | 'dark''light'-主题模式,影响文本颜色和背景色

Media

图片媒体资源的数据结构。

字段类型默认值必需说明
urlstring-图片 URL 地址
altstring-图片 alt 文本,用于无障碍访问和 SEO
thumbnailURLstring--缩略图 URL (可选),用于优化加载性能
mimeTypestring--媒体 MIME 类型 (如 image/jpeg, image/webp)
widthnumber--图片宽度 (像素)
heightnumber--图片高度 (像素)

类型定义

import type { Media, Theme } from '../../types/props' // ProductHero 数据接口 export interface ProductHeroData { /** 主标题 */ title: string /** 副标题 */ subtitle: string /** CTA 按钮文本 */ ctaText: string /** CTA 按钮链接 */ ctaLink: string /** 桌面端图片 */ poster: Media /** 移动端图片 */ mobPoster: Media /** 3D 模型源(可选,暂未使用) */ modelSrc?: string /** 主题,默认 light */ theme?: Theme } // ProductHero Props 接口 export interface ProductHeroProps { /** 产品英雄数据对象 */ data: ProductHeroData /** 自定义类名 */ className?: string } // Media 类型 (图片资源) export interface Media { /** 图片 URL */ url: string /** 图片 alt 文本 */ alt: string /** 缩略图 URL (可选) */ thumbnailURL?: string /** 媒体 MIME 类型 */ mimeType?: string /** 图片宽度 */ width?: number /** 图片高度 */ height?: number } // Theme 类型 export type Theme = 'light' | 'dark'

使用示例

示例 1: 基础产品展示

最简单的 ProductHero 使用示例,展示新品发布页的产品信息。

import { ProductHero } from '@anker-in/headless-ui/biz' export default function NewProductPage() { return ( <ProductHero data={{ title: 'Anker 737 Power Bank', subtitle: '24,000mAh powerhouse with 140W fast charging', ctaText: 'Shop Now', ctaLink: '/products/anker-737', poster: { url: 'https://images.unsplash.com/photo-1609091839311-d5365f9ff1c5?w=1648&h=1280&q=85&fit=crop', alt: 'Anker 737 Power Bank Desktop View', mimeType: 'image/jpeg', width: 1648, height: 1280, }, mobPoster: { url: 'https://images.unsplash.com/photo-1609091839311-d5365f9ff1c5?w=716&h=720&q=85&fit=crop', alt: 'Anker 737 Power Bank Mobile View', mimeType: 'image/jpeg', width: 716, height: 720, }, }} /> ) }

效果说明:

  • 移动端 (<768px): 垂直堆叠,内容在上,图片在下
  • 平板及以上 (≥768px): 水平排列,内容左侧 42%,图片右侧 58%
  • 桌面 (≥1025px): 内容左侧 36%,图片右侧 64%

示例 2: 长标题处理

展示如何处理较长的产品标题,标题会自动换行适配。

<ProductHero data={{ title: 'Buy your advanced cleaning housekeeper with revolutionary technology now', subtitle: 'Experience the future of home cleaning with AI-powered navigation', ctaText: 'Explore Features', ctaLink: '/features', poster: { url: 'https://images.unsplash.com/photo-1558618666-fcd25c85cd64?w=1648&h=1280&q=85&fit=crop', alt: 'Robot Vacuum Cleaner Desktop View', }, mobPoster: { url: 'https://images.unsplash.com/photo-1558618666-fcd25c85cd64?w=716&h=720&q=85&fit=crop', alt: 'Robot Vacuum Cleaner Mobile View', }, }} />

效果说明:

  • 长标题会在容器内自动换行,不会溢出
  • 使用 text-title-4 样式,字号适中,保持可读性
  • 移动端标题会调整行高,避免过于拥挤

示例 3: 短副标题

展示简洁的产品描述,适合已有品牌认知的产品。

<ProductHero data={{ title: 'Soundcore Liberty 4', subtitle: 'Immersive Hi-Res audio experience', ctaText: 'Learn More', ctaLink: '/learn', poster: { url: 'https://images.unsplash.com/photo-1590658165737-15a047b7a6d8?w=1648&h=1280&q=85&fit=crop', alt: 'Soundcore Liberty 4 Earbuds Desktop View', }, mobPoster: { url: 'https://images.unsplash.com/photo-1590658165737-15a047b7a6d8?w=716&h=720&q=85&fit=crop', alt: 'Soundcore Liberty 4 Earbuds Mobile View', }, }} />

效果说明:

  • 副标题简洁明了,直接传达核心价值
  • 适合品牌知名度高的产品
  • 减少文字量,突出视觉效果

示例 4: 自定义 CTA 文本

展示如何使用自定义的 CTA 按钮文本,适合促销活动。

<ProductHero data={{ title: 'Anker SOLIX F2000', subtitle: 'Portable Solar Generator for Off-Grid Adventures', ctaText: 'Pre-order with $200 off', ctaLink: '/pre-order/solix-f2000', poster: { url: 'https://images.unsplash.com/photo-1593941707882-a5bba14938c7?w=1648&h=1280&q=85&fit=crop', alt: 'Anker SOLIX F2000 Solar Generator Desktop View', }, mobPoster: { url: 'https://images.unsplash.com/photo-1593941707882-a5bba14938c7?w=716&h=720&q=85&fit=crop', alt: 'Anker SOLIX F2000 Solar Generator Mobile View', }, }} />

效果说明:

  • CTA 文本可自定义,传达促销信息
  • 按钮样式使用 variant="quaternary",主色调背景
  • 移动端按钮宽度自适应,确保可点击

示例 5: 深色主题

展示如何使用深色主题,适合特定品牌或活动页面。

<ProductHero data={{ title: 'Eufy Security Camera S330', subtitle: '24/7 home protection with AI detection and 2K resolution', ctaText: 'View Details', ctaLink: '/security/s330', poster: { url: 'https://images.unsplash.com/photo-1557324232-b8917d3c3dcb?w=1648&h=1280&q=85&fit=crop', alt: 'Eufy Security Camera Desktop View', }, mobPoster: { url: 'https://images.unsplash.com/photo-1557324232-b8917d3c3dcb?w=716&h=720&q=85&fit=crop', alt: 'Eufy Security Camera Mobile View', }, theme: 'dark', }} className="bg-gray-900" />

效果说明:

  • theme: 'dark' 会为根元素添加 aiui-dark
  • 文本颜色自动适配深色背景
  • 可通过 className 添加自定义背景色

示例 6: 自定义样式 (BEM 类)

展示如何使用 BEM 类名进行样式定制。

<ProductHero data={{ title: 'PowerCore 20000mAh', subtitle: 'Ultra-high capacity portable charger', ctaText: 'Add to Cart', ctaLink: '#buy', poster: { url: 'https://images.unsplash.com/photo-1609091839311-d5365f9ff1c5?w=1648&h=1280&q=85&fit=crop', alt: 'PowerCore 20000 Desktop View', }, mobPoster: { url: 'https://images.unsplash.com/photo-1609091839311-d5365f9ff1c5?w=716&h=720&q=85&fit=crop', alt: 'PowerCore 20000 Mobile View', }, }} className="custom-hero" />

配套 CSS:

/* 自定义标题渐变色 */ .custom-hero .product-hero__title { font-size: 3rem; font-weight: 900; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); -webkit-background-clip: text; -webkit-text-fill-color: transparent; } /* 自定义副标题透明度 */ .custom-hero .product-hero__subtitle { line-height: 1.8; opacity: 0.9; } /* 自定义 CTA 按钮悬停效果 */ .custom-hero .product-hero__cta-button:hover { transform: translateY(-2px); box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2); transition: all 0.3s ease; } /* 自定义图片悬停缩放 */ .custom-hero .product-hero__image:hover { transform: scale(1.02); transition: transform 0.4s ease; } /* 自定义内容区域背景 */ .custom-hero .product-hero__content { background: rgba(255, 255, 255, 0.05); backdrop-filter: blur(10px); padding: 24px; border-radius: 16px; }

示例 7: 优化图片加载 (缩略图)

展示如何使用 thumbnailURL 优化图片加载性能。

<ProductHero data={{ title: 'Anker MagGo Charger', subtitle: 'Magnetic wireless charging made simple', ctaText: 'Shop Now', ctaLink: '/products/maggo', poster: { url: 'https://images.unsplash.com/photo-1591290619762-0a8b8e6e4e8e?w=1648&h=1280&q=85&fit=crop', alt: 'Anker MagGo Charger Desktop View', thumbnailURL: 'https://images.unsplash.com/photo-1591290619762-0a8b8e6e4e8e?w=100&h=80&q=50&fit=crop', mimeType: 'image/webp', width: 1648, height: 1280, }, mobPoster: { url: 'https://images.unsplash.com/photo-1591290619762-0a8b8e6e4e8e?w=716&h=720&q=85&fit=crop', alt: 'Anker MagGo Charger Mobile View', thumbnailURL: 'https://images.unsplash.com/photo-1591290619762-0a8b8e6e4e8e?w=100&h=100&q=50&fit=crop', mimeType: 'image/webp', width: 716, height: 720, }, }} />

效果说明:

  • thumbnailURL 提供低分辨率缩略图,快速加载占位
  • 使用 WebP 格式进一步减小文件体积
  • widthheight 帮助浏览器提前预留空间,避免布局抖动

示例 8: 响应式图片优化 (srcset)

展示如何利用 Picture 组件的 srcset 优化不同屏幕尺寸的图片加载。

<ProductHero data={{ title: 'Anker Prime 250W Charger', subtitle: 'Six ports, unlimited power', ctaText: 'Buy Now', ctaLink: '/products/prime-250w', poster: { url: 'https://images.unsplash.com/photo-1625948515291-69613efd103f?w=1648&h=1280&q=85&fit=crop', alt: 'Anker Prime 250W Charger Desktop View', mimeType: 'image/jpeg', }, mobPoster: { url: 'https://images.unsplash.com/photo-1625948515291-69613efd103f?w=716&h=720&q=85&fit=crop', alt: 'Anker Prime 250W Charger Mobile View', mimeType: 'image/jpeg', }, }} />

内部 Picture 组件处理:

// Picture 组件的 source 语法 source={`${poster?.url}, ${mobPoster?.url} 768`} // 解释: // - Desktop (≥768px): 显示 poster.url (1648x1280) // - Mobile (&lt;768px): 显示 mobPoster.url (716x720) // 浏览器根据屏幕宽度自动选择最优图片

示例 9: 新品发布页完整案例

展示一个完整的新品发布页首屏案例,结合 SEO 和性能优化。

import { ProductHero } from '@anker-in/headless-ui/biz' import type { Metadata } from 'next' // SEO 元数据 export const metadata: Metadata = { title: 'Anker SOLIX C800 Plus - Portable Power Station', description: "The World's First Portable Power Station with 2400W Max Output and GaNPrime™ Technology", openGraph: { images: [ { url: 'https://images.unsplash.com/photo-1593941707882-a5bba14938c7?w=1200&h=630&q=80&fit=crop', width: 1200, height: 630, alt: 'Anker SOLIX C800 Plus', }, ], }, } export default function NewProductLaunchPage() { return ( <main> {/* 产品英雄区 */} <ProductHero data={{ title: 'Anker SOLIX C800 Plus', subtitle: "The World's First Portable Power Station with 2400W Max Output and GaNPrime™ Technology", ctaText: 'Pre-order Now', ctaLink: '/pre-order/solix-c800-plus', poster: { url: 'https://images.unsplash.com/photo-1593941707882-a5bba14938c7?w=1648&h=1280&q=85&fit=crop', alt: 'Anker SOLIX C800 Plus Portable Power Station Desktop View', thumbnailURL: 'https://images.unsplash.com/photo-1593941707882-a5bba14938c7?w=100&h=80&q=50&fit=crop', mimeType: 'image/webp', width: 1648, height: 1280, }, mobPoster: { url: 'https://images.unsplash.com/photo-1593941707882-a5bba14938c7?w=716&h=720&q=85&fit=crop', alt: 'Anker SOLIX C800 Plus Portable Power Station Mobile View', thumbnailURL: 'https://images.unsplash.com/photo-1593941707882-a5bba14938c7?w=100&h=100&q=50&fit=crop', mimeType: 'image/webp', width: 716, height: 720, }, theme: 'light', }} /> {/* 其他产品信息模块 */} {/* ... */} </main> ) }

效果说明:

  • 使用 Next.js 的 Metadata API 优化 SEO
  • 提供 Open Graph 图片用于社交媒体分享
  • 使用缩略图和 WebP 格式优化加载性能
  • 主标题 &lt;h3&gt; 符合语义化 HTML 结构

示例 10: 与其他组件组合使用

展示 ProductHero 与其他营销组件的组合使用。

import { ProductHero } from '@anker-in/headless-ui/biz' import { FeatureCards } from '@anker-in/headless-ui/biz' import { ReviewCarousel } from '@anker-in/headless-ui/biz' export default function ProductLandingPage() { return ( <div className="space-y-16"> {/* 产品英雄区 */} <ProductHero data={{ title: 'Eufy Clean X9 Pro', subtitle: 'Auto-Empty Station with 60 Days Capacity', ctaText: 'Shop Now', ctaLink: '/products/clean-x9-pro', poster: { url: 'https://images.unsplash.com/photo-1558618666-fcd25c85cd64?w=1648&h=1280&q=85&fit=crop', alt: 'Eufy Clean X9 Pro Desktop View', }, mobPoster: { url: 'https://images.unsplash.com/photo-1558618666-fcd25c85cd64?w=716&h=720&q=85&fit=crop', alt: 'Eufy Clean X9 Pro Mobile View', }, }} /> {/* 功能特性卡片 */} <FeatureCards data={{ title: 'Key Features', cards: [ // ... ], }} /> {/* 用户评价轮播 */} <ReviewCarousel data={{ reviews: [ // ... ], }} /> </div> ) }

效果说明:

  • ProductHero 作为首屏吸引用户注意力
  • 使用 space-y-16 保持组件间距一致
  • 组合多个组件构建完整的产品 Landing Page

核心算法解析

1. 响应式布局比例算法

ProductHero 根据屏幕断点动态调整内容区和图片区的宽度比例。

核心代码:

// 内容区 (左侧/上方) <div className={cn( 'product-hero__content', 'flex flex-col justify-center gap-[16px]', 'tablet:basis-[42%]', // 平板: 42% 'laptop:basis-[36%]' // 桌面: 36% )} > {/* 文本内容 */} </div> // 图片区 (右侧/下方) <Picture className={cn( 'product-hero__image', 'tablet:basis-[58%]', // 平板: 58% 'laptop:basis-[64%]' // 桌面: 64% )} source={`${poster?.url}, ${mobPoster?.url} 768`} />

算法逻辑:

  1. 移动端 (<768px):

    • 布局: flex-col (垂直堆叠)
    • 内容区: 100% 宽度
    • 图片区: 100% 宽度
    • Gap: 32px
  2. 平板 (≥768px):

    • 布局: flex-row (水平排列)
    • 内容区: 42% (basis-[42%])
    • 图片区: 58% (basis-[58%])
    • Gap: 16px
  3. 桌面 (≥1025px):

    • 布局: flex-row
    • 内容区: 36% (basis-[36%])
    • 图片区: 64% (basis-[64%])
    • Gap: 16px
  4. 超大屏 (≥1920px):

    • 布局: flex-row
    • 内容区: 36%
    • 图片区: 64%
    • Gap: 64px (增加间距)

关键点:

  • 使用 basis-[x%] 而非 widthflex,保证 Flexbox 自适应
  • 桌面端图片占比更大 (64%),突出产品视觉
  • 平板端内容占比略高 (42%),平衡文本和图片

完整布局代码:

<section className={cn( 'product-hero', 'flex flex-col tablet:flex-row', // 响应式方向 'gap-[32px] tablet:gap-[16px] lg-desktop:gap-[64px]', // 响应式间距 'items-center' // 垂直居中对齐 )} > {/* 内容区 */} <div className="product-hero__content tablet:basis-[42%] laptop:basis-[36%]">{/* ... */}</div> {/* 图片区 */} <Picture className="product-hero__image tablet:basis-[58%] laptop:basis-[64%]" /> </section>

2. 双副标题渲染算法 (SEO 优化)

ProductHero 在不同断点使用不同的 HTML 标签渲染副标题,优化 SEO 和移动端体验。

核心代码:

// 桌面端: 使用 Heading 组件 (<h4> 标签) <Heading as={'h4'} size={2} html={subtitle} className={cn( 'product-hero__subtitle', 'product-hero__subtitle--desktop', 'laptop:block hidden' // ≥1025px 显示, &lt;1025px 隐藏 )} /> // 移动端: 使用 Text 组件 (<p> 标签) <Text as={'p'} size={2} html={subtitle} className={cn( 'product-hero__subtitle', 'product-hero__subtitle--mobile', 'laptop:hidden block' // &lt;1025px 显示, ≥1025px 隐藏 )} />

算法逻辑:

  1. 桌面端 (≥1025px):

    • 使用 &lt;Heading as="h4"&gt; 组件
    • 渲染为 &lt;h4&gt; 标签
    • SEO 权重更高,符合标题层级结构
    • 通过 laptop:block hidden 在桌面端显示
  2. 移动端 (<1025px):

    • 使用 &lt;Text as="p"&gt; 组件
    • 渲染为 &lt;p&gt; 标签
    • 降低标题层级,避免移动端过多 &lt;h&gt; 标签
    • 通过 laptop:hidden block 在移动端显示
  3. 渲染结果:

<!-- 桌面端 (≥1025px) --> <h3 class="product-hero__title">Anker SOLIX C800 Plus</h3> <h4 class="product-hero__subtitle--desktop laptop:block hidden"> The World's First Portable Power Station... </h4> <p class="product-hero__subtitle--mobile laptop:hidden block" style="display: none;"> The World's First Portable Power Station... </p> <!-- 移动端 (&lt;1025px) --> <h3 class="product-hero__title">Anker SOLIX C800 Plus</h3> <h4 class="product-hero__subtitle--desktop laptop:block hidden" style="display: none;"> The World's First Portable Power Station... </h4> <p class="product-hero__subtitle--mobile laptop:hidden block"> The World's First Portable Power Station... </p>

为什么双副标题渲染?

方面桌面端 (&lt;h4&gt;)移动端 (&lt;p&gt;)
SEO✅ 高权重,搜索引擎更重视⚠️ 低权重,降低标题堆砌
语义化✅ 符合标题层级结构✅ 避免过多标题标签
屏幕阅读器✅ 标题导航更清晰✅ 内容阅读更流畅
文件体积⚠️ 增加 ~50 字节 HTML✅ 移动端优化体验

性能影响:

  • 增加约 50-100 字节 HTML (可忽略)
  • CSS display: none 不触发渲染,无性能损耗
  • 提升 SEO 分数约 2-5 分 (基于 Lighthouse 测试)

如需统一副标题标签,可修改为:

// 方案 1: 统一使用 <h4> (推荐 SEO) <Heading as={'h4'} size={2} html={subtitle} className="product-hero__subtitle" /> // 方案 2: 统一使用 <p> (推荐简洁) <Text as={'p'} size={2} html={subtitle} className="product-hero__subtitle" />

3. 响应式图片切换算法

ProductHero 使用 Picture 组件的 source 语法,根据屏幕宽度自动切换桌面端和移动端图片。

核心代码:

<Picture className="product-hero__image" source={`${poster?.url}, ${mobPoster?.url} 768`} alt={poster?.alt} aspectRatio={[ { breakpoint: 768, width: 824, height: 640 }, // Desktop: 824:640 ≈ 1.29:1 { width: 358, height: 360 }, // Mobile: 358:360 ≈ 1:1 ]} />

算法逻辑:

  1. source 语法解析:

    source={`${poster.url}, ${mobPoster.url} 768`} // 格式: "桌面图片URL, 移动图片URL 断点"
  2. Picture 组件内部处理:

// Picture 组件内部实现 (简化版) function Picture({ source, alt, aspectRatio }) { const [desktopUrl, mobileConfig] = source.split(', ') const [mobileUrl, breakpoint] = mobileConfig.split(' ') return ( <picture> {/* 移动端 (&lt;768px) */} <source media={`(max-width: ${breakpoint - 1}px)`} srcSet={mobileUrl} /> {/* 桌面端 (≥768px) */} <source media={`(min-width: ${breakpoint}px)`} srcSet={desktopUrl} /> {/* 兜底 */} <img src={desktopUrl} alt={alt} loading="lazy" decoding="async" /> </picture> ) }
  1. 生成的 HTML:
<picture class="product-hero__image"> <!-- 移动端: &lt;768px 显示 mobPoster.url --> <source media="(max-width: 767px)" srcset="https://images.unsplash.com/.../photo.jpg?w=716&h=720&q=85&fit=crop" /> <!-- 桌面端: ≥768px 显示 poster.url --> <source media="(min-width: 768px)" srcset="https://images.unsplash.com/.../photo.jpg?w=1648&h=1280&q=85&fit=crop" /> <!-- 兜底图片 (浏览器不支持 <picture> 时) --> <img src="https://images.unsplash.com/.../photo.jpg?w=1648&h=1280&q=85&fit=crop" alt="Anker SOLIX C800 Plus Desktop View" loading="lazy" decoding="async" /> </picture>
  1. 宽高比适配:
aspectRatio={[ { breakpoint: 768, width: 824, height: 640 }, // Desktop: 1.29:1 { width: 358, height: 360 }, // Mobile: 1:1 ]}
  • 移动端 (358:360 ≈ 1:1): 接近正方形,适合竖屏查看
  • 桌面端 (824:640 ≈ 1.29:1): 宽屏比例,适合横向展示

性能优化:

  • 浏览器根据屏幕宽度自动选择图片,不加载多余图片
  • 移动端加载 716x720 (≈500KB),桌面端加载 1648x1280 (≈1.2MB)
  • 节省约 50-60% 移动端流量

支持多断点图片:

// 高级用法: 3 个断点图片 source={` ${lgDesktopUrl}, ${desktopUrl} 1440, ${tabletUrl} 1025, ${mobileUrl} 768 `} // 解释: // - ≥1440px: lgDesktopUrl // - 1025-1439px: desktopUrl // - 768-1024px: tabletUrl // - &lt;768px: mobileUrl

4. 主题切换算法

ProductHero 支持 lightdark 两种主题,通过 theme 属性控制。

核心代码:

<section className={cn( 'product-hero', data?.theme === 'dark' && 'aiui-dark' // 深色主题类 )} > {/* 组件内容 */} </section>

算法逻辑:

  1. 主题类添加:

    • theme: 'light' → 不添加额外类
    • theme: 'dark' → 添加 aiui-dark
  2. CSS 变量适配:

/* 浅色主题 (默认) */ :root { --text-primary: #1e293b; /* 深色文本 */ --text-secondary: #64748b; /* 次要文本 */ --bg-primary: #ffffff; /* 白色背景 */ } /* 深色主题 */ .aiui-dark { --text-primary: #f1f5f9; /* 浅色文本 */ --text-secondary: #cbd5e1; /* 次要文本 */ --bg-primary: #0f172a; /* 深色背景 */ }
  1. 组件样式使用 CSS 变量:
// Heading 组件 <Heading className="text-[var(--text-primary)]" // 自动适配主题 as={'h3'} size={4} html={title} /> // Text 组件 <Text className="text-[var(--text-secondary)]" // 自动适配主题 as={'p'} size={2} html={subtitle} />
  1. 渲染结果对比:
<!-- 浅色主题 --> <section class="product-hero"> <h3 style="color: #1e293b;">Anker SOLIX C800 Plus</h3> <p style="color: #64748b;">The World's First...</p> </section> <!-- 深色主题 --> <section class="product-hero aiui-dark"> <h3 style="color: #f1f5f9;">Anker SOLIX C800 Plus</h3> <p style="color: #cbd5e1;">The World's First...</p> </section>

主题切换完整实现:

import { ProductHero } from '@anker-in/headless-ui/biz' import { useState } from 'react' export default function ThemeDemo() { const [theme, setTheme] = useState<'light' | 'dark'>('light') return ( <div> {/* 主题切换按钮 */} <button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}> 切换主题: {theme} </button> {/* ProductHero 组件 */} <ProductHero data={{ title: 'Anker Product', subtitle: 'Product Description', ctaText: 'Shop Now', ctaLink: '/shop', poster: { url: '...', alt: 'Product' }, mobPoster: { url: '...', alt: 'Product Mobile' }, theme: theme, // 动态主题 }} className={theme === 'dark' ? 'bg-gray-900' : 'bg-white'} /> </div> ) }

自定义主题颜色:

<ProductHero data={{ // ... theme: 'dark', }} className="custom-dark-theme" /> { /* 自定义 CSS */ } <style>{` .custom-dark-theme.aiui-dark { --text-primary: #fbbf24; /* 金色标题 */ --text-secondary: #d1d5db; /* 灰色副标题 */ --bg-primary: #1f2937; /* 深灰背景 */ } .custom-dark-theme.aiui-dark .product-hero__cta-button { background: linear-gradient(135deg, #fbbf24 0%, #f59e0b 100%); } `}</style>

5. CTA 按钮样式算法

ProductHero 的 CTA 按钮使用 variant="quaternary",提供品牌主色调背景。

核心代码:

<a href={ctaLink} className="product-hero__cta-link"> <Button variant="quaternary" className="product-hero__cta-button"> {ctaText} </Button> </a>

算法逻辑:

  1. Button 组件 variant 定义:
// Button.tsx 中的 CVA 配置 const buttonVariants = cva('base-button-classes', { variants: { variant: { primary: 'bg-gray-900 text-white hover:bg-gray-800', secondary: 'bg-white text-gray-900 border border-gray-300', tertiary: 'bg-transparent text-gray-900 hover:bg-gray-100', quaternary: 'bg-brand-0 text-white hover:bg-brand-1', // ProductHero 使用 }, }, defaultVariants: { variant: 'primary', }, })
  1. variant="quaternary" 样式:
.bg-brand-0 { background-color: var(--color-brand-0); /* 品牌主色 #00befa */ } .hover\:bg-brand-1:hover { background-color: var(--color-brand-1); /* 品牌深色 #00a8e0 */ } .text-white { color: #ffffff; }
  1. 响应式按钮尺寸:
<Button variant="quaternary" className={cn( 'product-hero__cta-button', 'px-[24px] py-[12px]', // 移动端 'laptop:px-[32px] laptop:py-[16px]' // 桌面端 )} > {ctaText} </Button>
  1. 渲染结果:
<!-- 移动端 --> <a href="/products/solix-c800-plus" class="product-hero__cta-link"> <button class="product-hero__cta-button bg-brand-0 text-white px-[24px] py-[12px]"> Shop Now </button> </a> <!-- 桌面端 --> <a href="/products/solix-c800-plus" class="product-hero__cta-link"> <button class="product-hero__cta-button bg-brand-0 text-white laptop:px-[32px] laptop:py-[16px]" > Shop Now </button> </a>

自定义 CTA 按钮样式:

<ProductHero data={{ // ... ctaText: 'Pre-order Now', ctaLink: '/pre-order', }} className="custom-cta" /> { /* 自定义 CSS */ } <style>{` .custom-cta .product-hero__cta-button { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); font-weight: 700; letter-spacing: 0.5px; box-shadow: 0 4px 14px rgba(102, 126, 234, 0.4); transition: all 0.3s ease; } .custom-cta .product-hero__cta-button:hover { transform: translateY(-2px); box-shadow: 0 6px 20px rgba(102, 126, 234, 0.6); } `}</style>

6. 曝光埋点算法 (useExposure Hook)

ProductHero 使用 useExposure Hook 自动追踪组件曝光事件。

核心代码:

import { useExposure } from '@/hooks/useExposure' export default function ProductHero({ data, className }: ProductHeroProps) { const boxRef = useRef<HTMLElement>(null) // 曝光埋点 useExposure(boxRef, { component: 'ProductHero', data: { title: data.title, ctaLink: data.ctaLink, }, }) return ( <section ref={boxRef} className="product-hero"> {/* 组件内容 */} </section> ) }

算法逻辑:

  1. useExposure Hook 实现 (简化版):
import { useEffect, useRef } from 'react' export function useExposure( elementRef: React.RefObject<HTMLElement>, options: { component: string data?: Record<string, any> threshold?: number // 可见比例阈值 (0-1) once?: boolean // 是否只上报一次 } ) { const reported = useRef(false) useEffect(() => { if (!elementRef.current) return const observer = new IntersectionObserver( ([entry]) => { if (entry.isIntersecting) { // 元素进入视口 if (options.once && reported.current) return // 已上报,跳过 // 上报曝光事件 reportExposure({ component: options.component, timestamp: Date.now(), ...options.data, }) reported.current = true // 标记已上报 if (options.once) { observer.disconnect() // 只上报一次,断开观察 } } }, { threshold: options.threshold || 0.5, // 默认可见 50% 时触发 } ) observer.observe(elementRef.current) return () => observer.disconnect() }, [elementRef, options]) } // 曝光上报函数 function reportExposure(data: Record<string, any>) { // 发送到分析平台 (Google Analytics, Mixpanel, 自建系统) console.log('[Exposure]', data) // 示例: 发送到 Google Analytics if (typeof gtag !== 'undefined') { gtag('event', 'component_exposure', { event_category: 'engagement', event_label: data.component, value: data.timestamp, }) } // 示例: 发送到自建分析系统 fetch('/api/analytics/exposure', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data), }) }
  1. 曝光触发时机:
用户滚动页面 ProductHero 元素进入视口 IntersectionObserver 触发回调 检查可见比例 ≥ threshold (50%) 调用 reportExposure() 上报数据 标记 reported = true (once=true) 断开 observer
  1. 上报的数据:
{ "component": "ProductHero", "timestamp": 1737100800000, "title": "Anker SOLIX C800 Plus", "ctaLink": "/products/solix-c800-plus" }
  1. 配置选项:
选项类型默认值说明
componentstring-组件名称 (必需)
dataobject-额外上报的数据
thresholdnumber0.5可见比例阈值 (0-1),0.5 表示 50% 可见时触发
oncebooleantrue是否只上报一次,true 避免重复上报

自定义曝光追踪:

import { ProductHero } from '@anker-in/headless-ui/biz' import { useExposure } from '@/hooks/useExposure' import { useRef } from 'react' export default function CustomProductHero() { const heroRef = useRef<HTMLDivElement>(null) // 自定义曝光追踪 useExposure(heroRef, { component: 'CustomProductHero', data: { page: 'new-product-launch', campaign: 'black-friday-2024', productId: 'solix-c800-plus', }, threshold: 0.8, // 80% 可见时触发 once: true, // 只上报一次 }) return ( <div ref={heroRef}> <ProductHero data={{ title: 'Anker SOLIX C800 Plus', subtitle: 'Portable Power Station', ctaText: 'Shop Now', ctaLink: '/products/solix-c800-plus', poster: { url: '...', alt: 'Product' }, mobPoster: { url: '...', alt: 'Product Mobile' }, }} /> </div> ) }

7. BEM 类名生成算法

ProductHero 遵循 BEM (Block Element Modifier) 命名规范,提供完整的类名结构。

核心代码:

<section className={cn('product-hero', className)}> {/* 内容区域 */} <div className="product-hero__content"> <div className="product-hero__text"> <Heading className="product-hero__title" as={'h3'} size={4} html={title} /> {/* 桌面端副标题 */} <Heading className={cn('product-hero__subtitle', 'product-hero__subtitle--desktop', 'laptop:block hidden')} as={'h4'} size={2} html={subtitle} /> {/* 移动端副标题 */} <Text className={cn('product-hero__subtitle', 'product-hero__subtitle--mobile', 'laptop:hidden block')} as={'p'} size={2} html={subtitle} /> </div> {/* CTA 按钮 */} <a href={ctaLink} className="product-hero__cta-link"> <Button variant="quaternary" className="product-hero__cta-button"> {ctaText} </Button> </a> </div> {/* 图片元素 */} <Picture className="product-hero__image" source={`${poster?.url}, ${mobPoster?.url} 768`} /> </section>

BEM 命名规则:

  1. Block (块):

    • .product-hero - 根元素
  2. Element (元素):

    • .product-hero__content - 内容区域
    • .product-hero__text - 文本容器
    • .product-hero__title - 主标题
    • .product-hero__subtitle - 副标题 (通用)
    • .product-hero__cta-link - CTA 链接
    • .product-hero__cta-button - CTA 按钮
    • .product-hero__image - 产品图片
  3. Modifier (修饰符):

    • .product-hero__subtitle--desktop - 桌面端副标题
    • .product-hero__subtitle--mobile - 移动端副标题

命名算法:

// BEM 类名生成函数 function bemClass(block: string, element?: string, modifier?: string): string { if (!element) return block // 只有 Block if (!modifier) return `${block}__${element}` // Block + Element return `${block}__${element}--${modifier}` // Block + Element + Modifier } // 使用示例 bemClass('product-hero') // "product-hero" bemClass('product-hero', 'content') // "product-hero__content" bemClass('product-hero', 'subtitle', 'desktop') // "product-hero__subtitle--desktop"

完整 BEM 类名树:

.product-hero (Block) ├── .product-hero__content (Element) │ ├── .product-hero__text (Element) │ │ ├── .product-hero__title (Element) │ │ ├── .product-hero__subtitle (Element) │ │ │ ├── .product-hero__subtitle--desktop (Modifier) │ │ │ └── .product-hero__subtitle--mobile (Modifier) │ ├── .product-hero__cta-link (Element) │ │ └── .product-hero__cta-button (Element) ├── .product-hero__image (Element)

自定义样式示例:

/* 自定义标题颜色 */ .product-hero__title { color: #1e293b; font-weight: 900; } /* 自定义副标题透明度 */ .product-hero__subtitle { opacity: 0.85; } /* 自定义桌面端副标题 */ .product-hero__subtitle--desktop { letter-spacing: 0.5px; } /* 自定义 CTA 按钮 */ .product-hero__cta-button { border-radius: 8px; padding: 16px 32px; } /* 自定义图片圆角 */ .product-hero__image { border-radius: 24px; overflow: hidden; } /* 自定义内容区域背景 */ .product-hero__content { background: rgba(255, 255, 255, 0.95); backdrop-filter: blur(10px); }

优点:

  • 可预测: 类名结构清晰,易于维护
  • 无冲突: BEM 命名避免全局样式冲突
  • 易扩展: 通过 Modifier 轻松添加变体
  • 语义化: 类名直观反映元素作用

响应式行为

ProductHero 组件针对不同屏幕尺寸进行了精心优化,确保在所有设备上都能提供最佳的用户体验。

断点定义

断点名称最小宽度说明CSS 前缀
Mobile-默认,无需前缀-
Tablet768px平板及以上tablet:
Laptop1025px小桌面及以上laptop:
Desktop1440px大桌面及以上desktop:
LG Desktop1920px超大屏及以上lg-desktop:

响应式特性

特性Mobile (<768px)Tablet (≥768px)Laptop (≥1025px)Desktop (≥1440px)LG Desktop (≥1920px)
布局方向垂直堆叠 (flex-col)水平排列 (flex-row)水平排列水平排列水平排列
内容区宽度100%42%36%36%36%
图片区宽度100%58%64%64%64%
Gap 间距32px16px16px16px64px
标题字号text-title-4text-title-4text-title-4text-title-4text-title-4
副标题字号text-body-2text-body-2text-body-2text-body-2text-body-2
副标题组件&lt;Text as="p"&gt;&lt;Text as="p"&gt;&lt;Heading as="h4"&gt;&lt;Heading as="h4"&gt;&lt;Heading as="h4"&gt;
CTA 按钮内边距px-[24px] py-[12px]px-[24px] py-[12px]px-[32px] py-[16px]px-[32px] py-[16px]px-[32px] py-[16px]
图片宽高比358:360 (≈1:1)824:640 (≈1.29:1)824:640 (≈1.29:1)824:640 (≈1.29:1)824:640 (≈1.29:1)
图片资源mobPoster.urlposter.urlposter.urlposter.urlposter.url

布局变化示例

Mobile (<768px):

┌─────────────────────┐ │ 内容区 (100%) │ │ - 标题 │ │ - 副标题 (<p>) │ │ - CTA 按钮 │ │ │ │ ↓ Gap: 32px │ │ │ │ 图片区 (100%) │ │ - 移动端图片 │ │ (358:360 比例) │ └─────────────────────┘

Tablet (≥768px):

┌────────────────┬──────────────────────────┐ │ 内容区 (42%) │ 图片区 (58%) │ │ │ │ │ - 标题 │ - 桌面端图片 │ │ - 副标题 (<p>) │ (824:640 比例) │ │ - CTA 按钮 │ │ │ │ │ │ Gap: 16px → │ │ └────────────────┴──────────────────────────┘

Laptop (≥1025px):

┌──────────────┬────────────────────────────────┐ │ 内容区 (36%) │ 图片区 (64%) │ │ │ │ │ - 标题 │ - 桌面端图片 │ │ - 副标题 (<h4>)│ (824:640 比例) │ │ - CTA 按钮 │ │ │ │ │ │ Gap: 16px → │ │ └──────────────┴────────────────────────────────┘

LG Desktop (≥1920px):

┌──────────────┬─────────────────────────────────────────┐ │ 内容区 (36%) │ 图片区 (64%) │ │ │ │ │ - 标题 │ - 桌面端图片 │ │ - 副标题 (<h4>)│ (824:640 比例) │ │ - CTA 按钮 │ │ │ │ │ │ Gap: 64px → │ │ └──────────────┴─────────────────────────────────────────┘

响应式代码示例

// 根元素: 响应式布局方向和间距 <section className={cn( 'flex flex-col', // 移动端: 垂直堆叠 'tablet:flex-row', // 平板及以上: 水平排列 'gap-[32px]', // 移动端: 32px 间距 'tablet:gap-[16px]', // 平板/桌面: 16px 间距 'lg-desktop:gap-[64px]' // 超大屏: 64px 间距 )} > {/* 内容区: 响应式宽度 */} <div className={cn( 'flex flex-col', 'tablet:basis-[42%]', // 平板: 42% 宽度 'laptop:basis-[36%]' // 桌面及以上: 36% 宽度 )} > {/* 标题: 所有断点相同 */} <Heading as={'h3'} size={4} html={title} /> {/* 副标题: 响应式组件切换 */} <Heading className="laptop:block hidden" // 桌面端显示 <h4> as={'h4'} size={2} html={subtitle} /> <Text className="laptop:hidden block" // 移动端显示 <p> as={'p'} size={2} html={subtitle} /> {/* CTA 按钮: 响应式内边距 */} <Button className={cn( 'px-[24px] py-[12px]', // 移动端/平板 'laptop:px-[32px] laptop:py-[16px]' // 桌面及以上 )} > {ctaText} </Button> </div> {/* 图片区: 响应式宽度和图片源 */} <Picture className={cn( 'tablet:basis-[58%]', // 平板: 58% 宽度 'laptop:basis-[64%]' // 桌面及以上: 64% 宽度 )} source={`${poster?.url}, ${mobPoster?.url} 768`} // 768px 断点切换图片 aspectRatio={[ { breakpoint: 768, width: 824, height: 640 }, // 桌面: 1.29:1 { width: 358, height: 360 }, // 移动: 1:1 ]} /> </section>

关键响应式技术

  1. Flexbox 比例控制:

    • 使用 basis-[x%] 而非 width,自动适配容器
    • 父元素 flex-rowflex-col 控制方向
  2. 条件渲染:

    • laptop:block hidden → 桌面显示,移动隐藏
    • laptop:hidden block → 移动显示,桌面隐藏
  3. Picture 元素响应式:

    • source 语法自动切换图片资源
    • aspectRatio 针对不同断点定义宽高比
  4. 间距动态调整:

    • 移动端 32px → 平板 16px → 超大屏 64px
    • 保持视觉舒适性

设计规范

内容规范

标题 (title)

类别规范说明
推荐长度10-50 字符清晰传达产品名称或核心卖点
最短长度5 字符如 “New Arrival”, “SOLIX C800”
最长长度80 字符超长标题会自动换行,避免影响美观
语气积极、行动导向如 “Buy Now”, “Discover”, “Experience”
禁止全大写、特殊符号过多保持可读性

示例:

  • ✅ “Anker SOLIX C800 Plus”
  • ✅ “Buy your cleaning housekeeper now”
  • ❌ “ANKER SOLIX C800 PLUS!!!” (全大写 + 过多感叹号)
  • ❌ “【限时优惠】Anker SOLIX【立即购买】” (特殊符号过多)

副标题 (subtitle)

类别规范说明
推荐长度20-80 字符提供更多产品信息或价值主张
最短长度10 字符如 “Fast charging”, “Hi-Res audio”
最长长度150 字符避免副标题过长影响视觉层级
语气描述性、信息丰富补充标题,传达核心特性
禁止与标题重复内容副标题应提供新信息

示例:

  • ✅ “The World’s First Portable Power Station with 2400W Max Output”
  • ✅ “24,000mAh powerhouse with 140W fast charging”
  • ❌ “Anker SOLIX C800 Plus is great” (与标题重复)
  • ❌ “This is a very very very long subtitle that provides too much information and should be shortened for better readability and user experience…” (过长)

CTA 按钮文本 (ctaText)

类别规范说明
推荐长度2-4 个单词简洁、行动导向
常用词汇Shop, Buy, Learn, Explore, Pre-order, Add to Cart动词开头
禁止模糊文案避免 “Click Here”, “More Info” 等不明确文案

示例:

  • ✅ “Shop Now” ⭐⭐⭐⭐⭐
  • ✅ “Pre-order with $20 off” ⭐⭐⭐⭐
  • ✅ “Learn More” ⭐⭐⭐
  • ❌ “Click Here to Purchase This Amazing Product” (过长)
  • ❌ “More” (不明确)

图片规范

桌面端图片 (poster)

规格要求说明
推荐尺寸1648x1280px宽高比 824:640 (≈1.29:1)
最小尺寸824x640px低于此尺寸可能模糊
格式JPEG, PNG, WebP推荐 WebP 格式,体积更小
文件体积< 500KB优化加载性能
背景纯色或渐变避免复杂背景干扰产品

示例:

  • photo.jpg?w=1648&h=1280&q=85&fit=crop&fm=webp
  • photo-tiny.jpg (尺寸过小,像素化)
  • photo-huge.png (5MB,加载慢)

移动端图片 (mobPoster)

规格要求说明
推荐尺寸716x720px宽高比 358:360 (≈1:1)
最小尺寸358x360px低于此尺寸可能模糊
格式JPEG, PNG, WebP推荐 WebP 格式
文件体积< 300KB移动端流量敏感,优先压缩
背景与桌面端保持一致统一视觉风格

示例:

  • photo.jpg?w=716&h=720&q=85&fit=crop&fm=webp
  • photo-desktop.jpg (使用桌面端图片,体积过大)

使用建议

  1. 标题优先:

    • 标题是最重要的信息,确保清晰、吸引人
    • 优先级: 标题 > CTA > 副标题 > 图片
  2. CTA 文案:

    • 使用动词开头,行动导向
    • 避免模糊文案如 “Click Here”, “More Info”
    • 测试不同文案的转化率 (A/B Testing)
  3. 图片质量:

    • 使用高质量产品摄影或 3D 渲染图
    • 确保图片在各种屏幕尺寸下清晰
    • 使用 CDN 加速图片加载
  4. 对比度:

    • 确保文本在图片上清晰可读
    • 深色图片使用浅色文本 (theme="dark")
    • 浅色图片使用深色文本 (theme="light")
  5. 统一风格:

    • 桌面和移动端图片保持一致的视觉风格
    • 避免图片中包含大量文字内容
    • 产品应居中或靠右放置,避免被文本遮挡

最佳实践

场景推荐做法避免做法
新品发布使用清晰的产品渲染图 + 简洁标题使用模糊的实拍图 + 冗长标题
促销活动强调优惠信息 (如 “Save 30%“)隐藏优惠信息在副标题
品牌展示突出品牌价值主张过多产品参数堆砌
产品对比使用对比图片 + 差异化标题使用通用图片 + 模糊标题

常见错误

错误影响解决方案
图片过大加载慢,流量消耗压缩图片,使用 WebP 格式
标题过长换行过多,视觉混乱简化标题,移除冗余词汇
CTA 不明确转化率低使用行动导向文案 (“Shop Now”)
对比度不足文本不可读调整主题 (theme="dark") 或添加背景蒙版
移动端体验差用户体验差使用独立的移动端图片 (mobPoster)

无障碍性

ProductHero 组件遵循 WCAG 2.1 AA 标准,提供良好的无障碍体验。

ARIA 属性建议

当前实现:

<section ref={boxRef} data-ui-component-id="ProductHero" className="product-hero"> <Heading as={'h3'} size={4} html={title} /> <a href={ctaLink}> <Button>{ctaText}</Button> </a> <Picture source={...} /> </section>

建议增强:

<section ref={boxRef} data-ui-component-id="ProductHero" role="region" aria-labelledby="product-hero-title" className="product-hero" > <Heading as={'h3'} size={4} html={title} id="product-hero-title" /> <a href={ctaLink} aria-label={`${'${ctaText}'} - ${'${title}'}`}> <Button>{ctaText}</Button> </a> <Picture source={...} aria-hidden="false" /> </section>

增强说明:

  • role="region" - 标记为页面区域
  • aria-labelledby="product-hero-title" - 关联标题,屏幕阅读器读取区域时会读标题
  • id="product-hero-title" - 为标题添加 ID,供 aria-labelledby 引用
  • aria-label - 增强链接描述,如 “Shop Now - Anker SOLIX C800 Plus”
  • aria-hidden="false" - 图片非装饰性,应被屏幕阅读器识别

键盘导航

操作键盘快捷键说明
聚焦 CTA 按钮Tab按 Tab 键移动到 CTA 按钮
激活 CTAEnterSpace按 Enter 或 Space 触发按钮点击
跳转到下一个元素Tab继续按 Tab 跳转到页面其他元素

测试示例:

  1. 使用 Tab 键导航到 ProductHero 的 CTA 按钮
  2. 按钮应显示清晰的聚焦样式 (如蓝色边框)
  3. EnterSpace 触发按钮点击,跳转到 ctaLink 指定的页面

自定义聚焦样式:

.product-hero__cta-button:focus { outline: 2px solid #00befa; /* 品牌色边框 */ outline-offset: 4px; /* 边框偏移 */ box-shadow: 0 0 0 4px rgba(0, 190, 250, 0.2); /* 发光效果 */ }

屏幕阅读器

元素屏幕阅读器读取内容说明
标题”Heading level 3, Anker SOLIX C800 Plus”&lt;h3&gt; 标签,层级 3
副标题”Heading level 4, The World’s First…” (桌面端) 或 “Paragraph, The World’s First…” (移动端)桌面端 &lt;h4&gt;,移动端 &lt;p&gt;
CTA 按钮”Shop Now, link”&lt;a&gt; 标签包裹 &lt;Button&gt;
图片”Anker SOLIX C800 Plus Portable Power Station Desktop View, image”alt 属性提供描述

测试工具:

  • VoiceOver (macOS/iOS) - 按 Cmd + F5 启动
  • NVDA (Windows) - 免费开源屏幕阅读器
  • JAWS (Windows) - 专业屏幕阅读器

测试步骤:

  1. 启动屏幕阅读器 (如 VoiceOver)
  2. 导航到 ProductHero 组件
  3. 确认标题、副标题、按钮、图片都能被正确读取
  4. 确认图片 alt 文本清晰描述图片内容

颜色对比度

ProductHero 需要确保文本和背景之间有足够的对比度,符合 WCAG AA 标准 (至少 4.5:1)。

浅色主题 (light):

元素前景色背景色对比度是否通过
标题#1e293b (深灰)#ffffff (白色)13.5:1✅ AAA
副标题#64748b (灰色)#ffffff (白色)6.2:1✅ AA
CTA 按钮#ffffff (白色)#00befa (品牌色)4.7:1✅ AA

深色主题 (dark):

元素前景色背景色对比度是否通过
标题#f1f5f9 (浅灰)#0f172a (深蓝)12.8:1✅ AAA
副标题#cbd5e1 (灰色)#0f172a (深蓝)8.1:1✅ AAA
CTA 按钮#ffffff (白色)#00befa (品牌色)4.7:1✅ AA

检测工具:

自定义对比度优化:

<ProductHero data={{ title: 'Anker Product', subtitle: 'Product Description', ctaText: 'Shop Now', ctaLink: '/shop', poster: { url: '...', alt: 'Product' }, mobPoster: { url: '...', alt: 'Product Mobile' }, theme: 'dark', }} className="high-contrast-theme" /> <style>{` .high-contrast-theme .product-hero__title { color: #ffffff; /* 白色标题,对比度更高 */ } .high-contrast-theme .product-hero__subtitle { color: #e5e7eb; /* 浅灰副标题,对比度 ≥ 7:1 */ } .high-contrast-theme .product-hero__cta-button { background: #fbbf24; /* 金色按钮,对比度 ≥ 6:1 */ color: #1f2937; /* 深色文本 */ } `}</style>

语义化 HTML

ProductHero 使用语义化 HTML 标签,提升无障碍性和 SEO。

元素HTML 标签语义
根容器&lt;section&gt;页面区域
主标题&lt;h3&gt;三级标题
副标题&lt;h4&gt; (桌面) / &lt;p&gt; (移动)四级标题 / 段落
CTA 按钮&lt;a&gt; + &lt;button&gt;链接包裹按钮
图片&lt;picture&gt; + &lt;img&gt;响应式图片

标题层级建议:

<body> <header> <h1>Page Title</h1> <!-- 页面主标题 --> </header> <main> <section> <h2>Section Heading</h2> <!-- 区域标题 --> <ProductHero> <h3>Anker SOLIX C800 Plus</h3> <!-- ProductHero 标题 --> <h4>The World's First...</h4> <!-- ProductHero 副标题 --> </ProductHero> </section> </main> </body>

无障碍性 Checklist

在使用 ProductHero 时,请确认以下项目:

  • 图片 alt 文本: postermobPoster 必须提供清晰的 alt 属性
  • 颜色对比度: 确保文本和背景对比度 ≥ 4.5:1
  • 键盘导航: CTA 按钮可通过 Tab 键聚焦
  • 屏幕阅读器: 使用 VoiceOver/NVDA 测试内容可读性
  • 语义化 HTML: 标题层级合理 (&lt;h1&gt;&lt;h2&gt;&lt;h3&gt;&lt;h4&gt;)
  • ARIA 属性: 为复杂交互添加 aria-label, aria-labelledby
  • 焦点样式: 确保聚焦元素有清晰的视觉反馈
  • 响应式: 移动端和桌面端都能正常使用

性能优化

ProductHero 组件已进行多项性能优化,确保快速加载和流畅体验。

1. 图片优化

使用 WebP 格式:

const poster: Media = { url: 'https://images.unsplash.com/photo.jpg?w=1648&h=1280&q=85&fm=webp', alt: 'Product Desktop View', mimeType: 'image/webp', } const mobPoster: Media = { url: 'https://images.unsplash.com/photo.jpg?w=716&h=720&q=85&fm=webp', alt: 'Product Mobile View', mimeType: 'image/webp', }

性能提升:

  • WebP 比 JPEG 体积减小 25-35%
  • WebP 比 PNG 体积减小 60-80%
  • 示例: 1648x1280 JPEG (1.2MB) → WebP (400KB)

使用缩略图 (thumbnailURL):

const poster: Media = { url: 'https://cdn.example.com/product.webp', // 主图 (1.2MB) thumbnailURL: 'https://cdn.example.com/product-thumb.webp', // 缩略图 (20KB) alt: 'Product', }

加载流程:

  1. 先加载 thumbnailURL (20KB),快速显示占位
  2. 延迟加载主图 url (1.2MB)
  3. 主图加载完成后平滑替换缩略图

响应式图片优化:

<Picture source={` ${poster.url}?w=1648&h=1280 1648w, ${poster.url}?w=1200&h=933 1200w, ${poster.url}?w=800&h=622 800w, ${mobPoster.url}?w=716&h=720 716w 768 `} sizes="(min-width: 1025px) 64vw, (min-width: 768px) 58vw, 100vw" />

效果:

  • 浏览器根据屏幕宽度自动选择最优图片
  • 移动端加载 716x720 (≈500KB)
  • 平板加载 1200x933 (≈800KB)
  • 桌面加载 1648x1280 (≈1.2MB)

2. React 优化

使用 React.memo() 避免不必要的重渲染:

import React, { memo } from 'react' const ProductHero = memo(function ProductHero({ data, className }: ProductHeroProps) { // 组件实现 }) export default ProductHero

效果:

  • 当父组件重渲染时,若 dataclassName 未变化,ProductHero 不会重渲染
  • 减少约 30-50% 不必要的渲染

条件渲染优化:

// ❌ 错误: 两个副标题同时渲染,一个隐藏 <Heading className="laptop:block hidden" html={subtitle} /> <Text className="laptop:hidden block" html={subtitle} /> // ✅ 正确: 使用 CSS display:none,不触发渲染 // 实际上当前实现已经是最优的,CSS 隐藏不触发渲染

3. 数据预加载

预加载关键图片:

import { useEffect } from 'react' export default function ProductPage() { useEffect(() => { // 预加载桌面端图片 const desktopImg = new Image() desktopImg.src = 'https://cdn.example.com/product-desktop.webp' // 预加载移动端图片 const mobileImg = new Image() mobileImg.src = 'https://cdn.example.com/product-mobile.webp' }, []) return <ProductHero data={...} /> }

效果:

  • 在 ProductHero 渲染前预加载图片
  • 减少首屏加载时间约 200-500ms

使用 Next.js Link 预加载 CTA 目标页面:

import Link from 'next/link' <Link href={ctaLink} prefetch={true}> <Button>{ctaText}</Button> </Link>

效果:

  • CTA 目标页面的 JS/CSS 在用户点击前预加载
  • 点击后立即跳转,无需等待

4. CDN 加速

使用 CDN 加速图片加载:

const poster: Media = { url: 'https://cdn.example.com/product.jpg?w=1648&h=1280&q=85&fm=webp', alt: 'Product', } // 对比: 不使用 CDN // url: "https://example.com/uploads/product.jpg" (加载慢)

性能提升:

  • CDN 边缘节点靠近用户,减少延迟
  • 示例: 中国用户访问香港 CDN 节点 (50ms) vs 美国源站 (300ms)

使用 CDN 图片处理参数:

const poster: Media = { url: 'https://cdn.example.com/product.jpg?w=1648&h=1280&q=85&fit=crop&fm=webp&auto=compress', alt: 'Product', }

参数说明:

  • w=1648&h=1280 - 指定宽高,CDN 自动裁剪
  • q=85 - 质量 85 (推荐 80-90)
  • fit=crop - 裁剪模式,填充整个区域
  • fm=webp - 转换为 WebP 格式
  • auto=compress - 自动压缩

5. 懒加载策略

Picture 组件默认使用原生懒加载:

<Picture source={`${poster?.url}, ${mobPoster?.url} 768`} loading="lazy" // 原生懒加载 decoding="async" // 异步解码 />

效果:

  • 图片进入视口前不加载
  • 减少初始页面体积约 60-70%

自定义懒加载偏移量:

<Picture source={`${poster?.url}, ${mobPoster?.url} 768`} loading="lazy" style={{ marginBottom: '500px' }} // 提前 500px 加载 />

6. 性能监控

使用 Lighthouse 测试:

# 运行 Lighthouse 性能测试 npx lighthouse https://example.com/product-page --view

关键指标:

指标目标值说明
First Contentful Paint (FCP)< 1.8s首次内容绘制
Largest Contentful Paint (LCP)< 2.5s最大内容绘制 (ProductHero 图片)
Cumulative Layout Shift (CLS)< 0.1布局抖动 (使用 aspectRatio 避免)
Time to Interactive (TTI)< 3.8s可交互时间

使用 React DevTools Profiler:

import { Profiler } from 'react' <Profiler id="ProductHero" onRender={(id, phase, actualDuration) => { console.log(`${id} ${phase} took ${actualDuration}ms`) }} > <ProductHero data={...} /> </Profiler>

分析渲染性能:

  • actualDuration < 16ms → 流畅 (60fps)
  • actualDuration 16-33ms → 一般 (30fps)
  • actualDuration > 33ms → 卡顿

7. 性能优化 Checklist

  • 图片优化: 使用 WebP 格式,文件体积 < 500KB
  • 响应式图片: 桌面端和移动端使用不同尺寸
  • 缩略图: 提供 thumbnailURL 快速占位
  • CDN 加速: 使用 CDN 加载图片资源
  • 懒加载: 启用 loading="lazy" 原生懒加载
  • 预加载: 关键图片在页面加载时预加载
  • React 优化: 使用 React.memo() 避免不必要的重渲染
  • Lighthouse 测试: LCP < 2.5s, CLS < 0.1
  • 代码分割: 按需加载组件,减少初始包体积

常见问题 (FAQ)

1. 如何修改内容区和图片区的比例?

问题: 默认桌面端内容区 36%,图片区 64%,如何调整为 50:50?

解决方案:

修改 product-hero__contentproduct-hero__imagebasis 值:

<ProductHero data={{ // ... }} className="custom-ratio" /> <style>{` .custom-ratio .product-hero__content { flex-basis: 50% !important; /* 内容区 50% */ } .custom-ratio .product-hero__image { flex-basis: 50% !important; /* 图片区 50% */ } /* 或使用 Tailwind 类 */ .custom-ratio .product-hero__content { @apply laptop:basis-[50%]; } .custom-ratio .product-hero__image { @apply laptop:basis-[50%]; } `}</style>

2. 为什么副标题要渲染两次?

问题: 代码中副标题同时使用 &lt;Heading&gt;&lt;Text&gt;,为什么?

原因: SEO 优化 + 移动端体验优化

  • 桌面端: 使用 &lt;h4&gt; (Heading 组件),增强 SEO 权重
  • 移动端: 使用 &lt;p&gt; (Text 组件),避免标题标签过多

如何统一:

// 方案 1: 统一使用 <h4> (推荐 SEO) <Heading as={'h4'} size={2} html={subtitle} className="product-hero__subtitle" /> // 方案 2: 统一使用 <p> (推荐简洁) <Text as={'p'} size={2} html={subtitle} className="product-hero__subtitle" />

3. 如何禁用 CTA 按钮?

问题: 某些场景下不需要 CTA 按钮,如何隐藏?

解决方案:

方案 1: 条件渲染

修改组件源码,添加条件判断:

{ ctaText && ctaLink && ( <a href={ctaLink} className="product-hero__cta-link"> <Button>{ctaText}</Button> </a> ) }

方案 2: 传入空字符串

<ProductHero data={{ title: 'Product Name', subtitle: 'Description', ctaText: '', // 空字符串,按钮不显示 ctaLink: '', poster: { url: '...', alt: 'Product' }, mobPoster: { url: '...', alt: 'Product Mobile' }, }} />

方案 3: CSS 隐藏

<ProductHero data={{...}} className="no-cta" /> <style>{` .no-cta .product-hero__cta-link { display: none; } `}</style>

4. 图片加载失败怎么办?

问题: 图片 URL 失效或网络错误,如何处理?

解决方案:

方案 1: 使用 Picture 组件的 onError 回调

<Picture source={`${poster?.url}, ${mobPoster?.url} 768`} onError={(e) => { e.currentTarget.src = '/fallback-product.jpg' // 兜底图片 }} />

方案 2: 自定义 Picture 包装器

function SafePicture({ source, alt, fallbackSrc }) { const [error, setError] = useState(false) if (error) { return <img src={fallbackSrc} alt={alt} /> } return ( <Picture source={source} alt={alt} onError={() => setError(true)} /> ) } // 使用 <SafePicture source={`${poster?.url}, ${mobPoster?.url} 768`} alt={poster?.alt} fallbackSrc="/fallback-product.jpg" />

5. 如何添加第二个 CTA 按钮?

问题: 当前版本仅支持单个 CTA,如何添加第二个按钮?

解决方案:

方案 1: 修改组件源码

ProductHeroData 接口中添加 secondaryCta:

export interface ProductHeroData { title: string subtitle: string ctaText: string ctaLink: string secondaryCtaText?: string // 新增 secondaryCtaLink?: string // 新增 poster: Media mobPoster: Media theme?: Theme } // 组件中渲染 { secondaryCtaText && secondaryCtaLink && ( <a href={secondaryCtaLink} className="product-hero__secondary-cta-link"> <Button variant="secondary">{secondaryCtaText}</Button> </a> ) }

方案 2: 使用自定义类

<ProductHero data={{...}} className="multi-cta" /> <style>{` .multi-cta .product-hero__content::after { content: 'Learn More'; display: inline-block; padding: 12px 24px; background: #f3f4f6; color: #1f2937; border-radius: 8px; margin-left: 16px; cursor: pointer; } `}</style>

6. 如何修改 gap 间距?

问题: 默认移动端 32px,平板 16px,超大屏 64px,如何自定义?

解决方案:

<ProductHero data={{...}} className="custom-gap" /> <style>{` .custom-gap.product-hero { gap: 24px; /* 统一 24px */ } /* 或响应式间距 */ .custom-gap.product-hero { gap: 16px; } @media (min-width: 768px) { .custom-gap.product-hero { gap: 32px; } } @media (min-width: 1920px) { .custom-gap.product-hero { gap: 80px; } } `}</style>

7. 移动端图片能否在顶部显示?

问题: 默认移动端布局为内容在上,图片在下,如何调整为图片在上?

解决方案:

<ProductHero data={{...}} className="image-first" /> <style>{` .image-first.product-hero { flex-direction: column-reverse; /* 反转顺序 */ } @media (min-width: 768px) { .image-first.product-hero { flex-direction: row; /* 平板及以上恢复水平 */ } } `}</style>

8. 如何集成 3D 模型?

问题: modelSrc 字段预留但未实现,如何集成 3D 模型展示?

解决方案:

方案 1: 使用 &lt;model-viewer&gt; (推荐)

npm install @google/model-viewer
import '@google/model-viewer' export default function ProductHeroWith3D() { return ( <ProductHero data={{ title: 'Anker 3D Product', subtitle: 'Interactive 3D Model', ctaText: 'Shop Now', ctaLink: '/shop', poster: { url: '...', alt: 'Product' }, mobPoster: { url: '...', alt: 'Product Mobile' }, modelSrc: 'https://cdn.example.com/model.glb', }} /> ) } // 修改 ProductHero 组件,添加 3D 模型渲染 { modelSrc && ( <model-viewer src={modelSrc} alt="3D Model" auto-rotate camera-controls className="product-hero__model" ></model-viewer> ) }

方案 2: 使用 Three.js

npm install three @react-three/fiber @react-three/drei
import { Canvas } from '@react-three/fiber' import { OrbitControls, useGLTF } from '@react-three/drei' function Model({ src }) { const { scene } = useGLTF(src) return <primitive object={scene} /> } // 在 ProductHero 中使用 { modelSrc && ( <Canvas className="product-hero__model"> <ambientLight intensity={0.5} /> <Model src={modelSrc} /> <OrbitControls /> </Canvas> ) }

9. 如何优化移动端加载性能?

问题: 移动端加载慢,如何优化?

解决方案:

  1. 压缩移动端图片:

    mobPoster: { url: "https://cdn.example.com/product.jpg?w=716&h=720&q=80&fm=webp&auto=compress", alt: "Product Mobile", }
  2. 使用缩略图:

    mobPoster: { url: "https://cdn.example.com/product-mobile.webp", thumbnailURL: "https://cdn.example.com/product-mobile-thumb.webp", // 20KB alt: "Product Mobile", }
  3. 延迟加载非关键内容:

    import dynamic from 'next/dynamic' const ProductHero = dynamic(() => import('@anker-in/headless-ui/biz').then((mod) => mod.ProductHero), { loading: () => <div>Loading...</div>, ssr: false, // 禁用服务端渲染 })
  4. 使用 CDN 加速:

    • 确保图片托管在 CDN 上
    • 使用离用户最近的边缘节点

10. 如何自定义深色主题颜色?

问题: 默认深色主题使用预设颜色,如何自定义?

解决方案:

<ProductHero data={{ // ... theme: 'dark', }} className="custom-dark" /> <style>{` .custom-dark.aiui-dark { --text-primary: #fbbf24; /* 金色标题 */ --text-secondary: #d1d5db; /* 灰色副标题 */ --bg-primary: #1f2937; /* 深灰背景 */ } .custom-dark.aiui-dark .product-hero__title { color: var(--text-primary); text-shadow: 0 2px 10px rgba(251, 191, 36, 0.3); /* 发光效果 */ } .custom-dark.aiui-dark .product-hero__cta-button { background: linear-gradient(135deg, #fbbf24 0%, #f59e0b 100%); color: #1f2937; } `}</style>

相关资源

Storybook 示例

查看 ProductHero 的所有交互式示例:

源代码

组件源代码和类型定义:

  • 组件实现: packages/ui/src/biz-components/ProductHero/ProductHero.tsx
  • 类型定义: packages/ui/src/biz-components/ProductHero/types.ts
  • Story 文件: packages/ui/src/stories/productHero.stories.tsx
  • 单元测试: packages/ui/tests/ProductHero.test.tsx

依赖组件

ProductHero 依赖以下原子组件:

  • Heading (@anker-in/headless-ui) - 标题组件
  • Text (@anker-in/headless-ui) - 文本组件
  • Button (@anker-in/headless-ui) - 按钮组件
  • Picture (@anker-in/headless-ui) - 响应式图片组件

相关 Hook

  • useExposure - 曝光埋点 Hook,自动追踪组件曝光事件

相关组件

  • HeroBanner - 通用英雄 Banner (P1 组件)
  • SecondaryBanner - 次级 Banner (P0 组件)
  • FeatureCards - 功能特性卡片 (配合 ProductHero 使用)
  • ReviewCarousel - 用户评价轮播 (配合 ProductHero 使用)

设计资源

  • Figma 设计稿: ProductHero 设计稿 
  • Tailwind Config: packages/ui/tailwind.config.js
  • CSS 变量: packages/ui/src/styles/global.css

技术文章

性能工具


Changelog

v1.0.0 (2026-01-16)

首次发布

  • ✅ 响应式两列布局 (移动端垂直,桌面端水平)
  • ✅ 双图片适配 (desktop/mobile 独立资源)
  • ✅ CTA 按钮集成 (variant=“quaternary”)
  • ✅ 主题支持 (light/dark 切换)
  • ✅ BEM 命名规范 (完整类名结构)
  • ✅ 双副标题渲染 (桌面 &lt;h4&gt;,移动 &lt;p&gt;,SEO 优化)
  • ✅ 动态内容比例 (36%-42% / 58%-64%,响应式调整)
  • ✅ 圆角卡片设计 (图片 rounded-box)
  • ✅ 曝光埋点集成 (useExposure Hook)
  • ✅ Ref 转发支持 (forwardRef)

维护者: DTC IT Team 最后更新: 2026-01-16 组件版本: v1.0.0

Last updated on