Nuxt UI v4 PageCTA 组件实战指南:用 UPageCTA 构建高质量的页面转化区

原创2026-10-09 00:28:361,430 阅读
文章标签:前端UI组件

Nuxt UI v4 PageCTA 组件实战指南:用 UPageCTA 构建高质量的页面转化区

PageCTA 是 Nuxt UI v4 提供的「行动号召」页面组件,用于在落地页、营销页或产品页面中集中呈现标题、描述与操作按钮,并通过 default 插槽灵活放置插画或图片。本文基于 page-cta.md 官方文档,结合 PageCTA.vue 源码与 page-cta.ts 主题配置,完整讲解 UPageCTA 的用法、全部 Props/Slots、5 种变体样式与底层实现原理,帮助你在 Nuxt 应用中快速搭建专业、可定制、无障碍的 CTA 区块。

组件定位:页面骨架中的「转化收口」节点

UPageCTA 是 Nuxt UI 页面级组件家族中的一员,与 PageHero、PageSection 等组件共同构成完整的页面叙事结构。它的典型使用场景是页面末尾的收尾转化区——一个包含标题、说明文案、按钮组与插图的醒目区块。

官方文档给出的定位是:

The PageCTA component provides a flexible way to display a call to action in your pages with an illustration in the default slot.

也就是说,PageCTA 的核心能力是:以默认插槽承载插图(Illustration),配合标题、描述与按钮,组成一个高辨识度的转化区块。

从源码结构看,PageCTA 的内部骨架非常清晰(PageCTA.vue):

Primitive(root)
├── top 插槽
├── UContainer(container)       # 内部使用 Container 组件承载内容
│   ├── wrapper
│   │   ├── header
│   │   │   ├── title(h2)
│   │   │   └── description
│   │   ├── body 插槽
│   │   └── footer
│   │       └── links(渲染 UButton 列表)
│   └── default 插槽(插图)
└── bottom 插槽

其中 wrapper 只在存在 header、body、footer、links 相关内容时才渲染;而 default 插槽(插图)独立于 wrapper 之外,与文本内容在网格布局中并排或上下排列。

基础用法:放在哪里、怎么写

PageCTA 既可以直接放在页面里,也可以嵌套在 PageSection 中。官方文档给出的页面级组合示例如下:

<template>
  <UPageHero />

  <UPageCTA class="rounded-none" />

  <UPageSection />

  <UPageSection :ui="{ container: 'px-0' }">
    <UPageCTA class="rounded-none sm:rounded-xl" />
  </UPageSection>

  <UPageSection />
</template>

这里展示了两种常见排布:

  • 直接放置于页面中,紧随 UPageHero 之后,充当内容与转化之间的过渡区块;
  • 嵌套在 UPageSection 内,通过 :ui="{ container: 'px-0' }" 去掉内边距,让 CTA 横跨整个视口宽度。

提示:使用 px-0 与 rounded-none 类可以让 CTA 在移动端填满页面边缘(消除内边距与圆角),桌面端再通过 sm:rounded-xl 恢复圆角。这是官方文档明确推荐的处理手法。

一个带插图的完整示例(官方 code-preview 原样)如下:

::u-page-c-t-a
---
title: 'Trusted and supported by our amazing community'
description: 'Preview the latest Tailwind CSS and get started with Nuxt UI.'
orientation: horizontal
links:
  - label: 'Get started'
    color: 'neutral'
  - label: 'Learn more'
    color: 'neutral'
    variant: 'subtle'
    trailingIcon: 'i-lucide-arrow-right'
---

:img{src="https://picsum.photos/640/616" width="320" height="308" alt="Illustration" class="w-full rounded-lg"}
::

将上图写法对应到实际 Vue 模板,等价于:

<template>
  <UPageCTA
    title="Trusted and supported by our amazing community"
    description="Preview the latest Tailwind CSS and get started with Nuxt UI."
    orientation="horizontal"
    :links="[
      { label: 'Get started', color: 'neutral' },
      { label: 'Learn more', color: 'neutral', variant: 'subtle', trailingIcon: 'i-lucide-arrow-right' }
    ]"
  >
    <img src="/images/illustration.png" class="w-full rounded-lg" alt="Illustration" />
  </UPageCTA>
</template>

Title:设置标题

通过 title prop 设置 CTA 的标题文本:

<template>
  <UPageCTA title="Trusted and supported by our amazing community" />
</template>

标题在源码中渲染为 h2 元素(PageCTA.vue),并带有 data-slot="title" 属性,便于选择器定位与样式覆盖。主题默认样式为 text-3xl sm:text-4xl text-pretty tracking-tight font-bold text-highlighted(page-cta.ts),即 3xl→4xl 的响应式字号、紧凑字距与加粗字形。

Description:设置描述文案

通过 description prop 设置 CTA 的描述文字,渲染在标题下方:

<template>
  <UPageCTA
    title="Trusted and supported by our amazing community"
    description="We've built a strong, lasting partnership. Their trust is our driving force, propelling us towards shared success."
  />
</template>

默认样式为 text-base sm:text-lg text-muted。需要注意一个联动细节:主题中存在 title: { true: { description: 'mt-6' } } 的组合变体(page-cta.ts)——当标题存在时,描述会自动获得 mt-6 的上间距,无需手动补类。

Links:渲染按钮组

links prop 接受一组 ButtonProps<a href="https://link.gitcode.com/i/8cde05d695e39ff334ce4c2f58a67819" target="_blank">],在描述下方渲染为按钮列表。源码中每个链接都被渲染为 size="lg" 的 [UButton(PageCTA.vue):

<template>
  <UPageCTA
    title="Trusted and supported by our amazing community"
    description="We've built a strong, lasting partnership."
    :links="[
      { label: 'Get started', color: 'neutral' },
      { label: 'Learn more', color: 'neutral', variant: 'subtle', trailingIcon: 'i-lucide-arrow-right' }
    ]"
  />
</template>

因此 links 中的每一项都完全遵循 Button 组件的 Props 体系,包括 label、color、variant、icon、trailingIcon、to、target 等(ButtonProps 继承自 LinkProps 并扩展了图标与颜色相关属性)。按钮容器默认使用 flex flex-wrap gap-x-6 gap-y-3 布局,支持换行且横向间距 6、纵向间距 3。

Variant:5 种视觉变体

variant prop 控制 CTA 的整体视觉风格,默认值为 outline。主题(page-cta.ts)定义了 5 种变体:

变体 root 样式 说明
solid bg-inverted text-inverted 反转底色,文字与背景互换,视觉冲击最强
outline(默认) bg-default ring ring-default 背景色 + 外描边,层次清晰
soft bg-elevated/50 半透明浅色底,柔和低调
subtle bg-elevated/50 ring ring-default 浅色底 + 描边,介于 soft 与 outline 之间
naked (无) 无背景无描边,完全裸样式,便于自定义
<template>
  <UPageCTA
    title="Trusted and supported by our amazing community"
    description="We've built a strong, lasting partnership."
    variant="soft"
    :links="[
      { label: 'Get started', color: 'neutral' },
      { label: 'Learn more', color: 'neutral', variant: 'subtle', trailingIcon: 'i-lucide-arrow-right' }
    ]"
  />
</template>

各变体对 description 的颜色也有联动调整(solid 为 text-dimmed、outline/naked 为 text-muted、soft/subtle 为 text-toned),保证不同背景下文案对比度始终合格。

提示:使用 solid 变体时,如果 links 中的按钮仍保持默认配色会与反转背景产生反差,官方文档建议在 links 插槽内的按钮上应用 light 或 dark 类来反转按钮颜色,保证可读性。

Orientation 与 Reverse:控制图文排布

Orientation

orientation prop 决定 default 插槽(插图)与文本内容的排布方向,默认值为 vertical:

  • vertical:文本与插图上下排列,标题、描述、按钮居中显示(主题会给 title/description 加 text-center、给 links 加 justify-center);
  • horizontal:容器切换为双列网格(lg:grid-cols-2 lg:items-center),文本居左、插图居右,描述额外获得 text-pretty 排版优化。
<template>
  <UPageCTA
    title="Trusted and supported by our amazing community"
    description="We've built a strong, lasting partnership."
    orientation="horizontal"
    :links="[{ label: 'Get started', color: 'neutral' }]"
  >
    <img src="/images/illustration.png" class="w-full rounded-lg" alt="Illustration" />
  </UPageCTA>
</template>

Reverse

reverse prop(默认 false)用于反转 default 插槽的排列顺序。从主题看,reverse: { true: { wrapper: 'order-last' } }(page-cta.ts)——开启后,承载标题/描述的 wrapper 块变为 order-last,在网格布局中会排到插图之后,实现「插图在左、文本在右」的反向排布。

<template>
  <UPageCTA
    title="Trusted and supported by our amazing community"
    description="We've built a strong, lasting partnership."
    orientation="horizontal"
    reverse
    :links="[{ label: 'Get started', color: 'neutral' }]"
  >
    <img src="/images/illustration.png" class="w-full rounded-lg" alt="Illustration" />
  </UPageCTA>
</template>

一个值得注意的源码细节:当 orientation="horizontal" 且未提供 default 插槽时,PageCTA 会渲染一个 hidden lg:block 的占位元素(PageCTA.vue,prefix('hidden lg:block') 中的 prefix 来自 usePrefix),用于在桌面端保持双列网格的占位,避免纯文本模式下布局失衡。

插槽体系:9 个插槽实现完全自定义

PageCTA 共暴露 9 个插槽(类型定义见 PageCTA.vue),官方测试 PageCTA.spec.ts 对全部插槽逐一覆盖验证:

插槽 位置/作用 默认内容
top root 内部最顶部,可放发光/背景装饰 无
header 标题与描述的容器 标题 + 描述
title 标题位置,可自定义标题节点 {{ title }}
description 描述位置,可自定义描述节点 {{ description }}
body header 与 footer 之间的自由内容区 无
footer 底部区域,可整体替换按钮区 links 按钮组
links 按钮组容器 遍历渲染 UButton
default 插图/媒体内容区 无(horizontal 时有占位元素)
bottom root 内部最底部 无

插槽与 props 的渲染存在联动逻辑:例如只有 props.title || slots.title 存在时才渲染 h2;只有当 props.links?.length || slots.links 时才渲染 links 容器。这意味着整个 wrapper 结构会根据实际传入内容「按需渲染」,不传内容就不会产生多余 DOM。

官方文档站自身的落地页(ThemeStudioViewLanding.vue)是插槽组合的典型范例——它使用 variant="naked" 配合 #top(放置 .landing-glow 发光装饰)、#title、#description、#links(两个自定义 UButton)构建了一个完全定制的转化区,并借助 :ui prop 将容器收窄为 max-w-3xl text-center:

<UPageCTA
  variant="naked"
  :ui="{
    root: 'py-24 sm:py-32',
    container: 'max-w-3xl text-center',
    title: 'lg:text-5xl tracking-tighter',
    description: 'mx-auto max-w-sm leading-relaxed text-dimmed'
  }"
>
  <template #top>
    <div class="landing-glow absolute bottom-0 left-1/2 h-1/2 w-2/3 -translate-x-1/2" aria-hidden="true" />
  </template>

  <template #title>
    <span v-reveal class="inline-block">Ready to stop<br>firefighting?</span>
  </template>

  <template #links>
    <div v-reveal="200" class="flex flex-col items-center justify-center gap-6">
      <UButton label="Start for free" variant="solid" size="xl" />
      <UButton label="npx telemetry init" color="neutral" variant="subtle" size="xl" />
    </div>
  </template>
</UPageCTA>

API 一览:Props 与 Slots

Props

Prop 类型 默认值 说明
as any 'div' 组件渲染成的元素或组件,如 section、article
class any — 附加到 root 的类名
title string — CTA 标题
description string — CTA 描述文案
orientation 'vertical' | 'horizontal' 'vertical' 默认插槽与文本的排布方向
reverse boolean false 反转默认插槽的排列顺序
variant 'solid' | 'outline' | 'soft' | 'subtle' | 'naked' 'outline' 视觉变体
links ButtonProps[] — 描述下方展示的按钮列表
ui Partial<PageCTASlots> — 逐插槽覆盖样式

说明:orientation 与 reverse 的默认值由源码中的 withDefaults 显式声明(PageCTA.vue),variant 默认 outline 则来自主题文件的 defaultVariants(page-cta.ts);as 的默认 'div' 见组件 Props 类型注释(PageCTA.vue)。

Slots

top、header、title、description、body、footer、links、default、bottom,共 9 个插槽,详见上文插槽表格。

主题定制:ui prop 与 appConfig

PageCTA 的样式由 tv(Tailwind Variant 的封装)驱动,主题定义在 src/theme/page-cta.ts,支持两种覆盖层级:

  1. 组件级 ui prop:例如 :ui="{ container: 'max-w-5xl' }" 覆盖容器宽度,:ui="{ root: 'py-24 sm:py-32' }" 调整内边距。所有插槽位(root、container、wrapper、header、title、description、body、footer、links)均可单独覆盖,源码通过 ui.root({ class: <a href="https://link.gitcode.com/i/ebc48b06cfbc5f2d478e7f4da7eb172c" target="_blank">props.ui?.root, props.class] }) 等调用实现类名合并([PageCTA.vue)。
  2. 应用级 appConfig.ui.pageCTA:在 app.config.ts 中全局覆写,源码通过 tv({ extend: theme, ...(appConfig.ui?.pageCTA || {}) }) 将全局配置与默认主题合并(PageCTA.vue),实现全站统一的 CTA 风格。

同时,PageCTA 内部嵌入了 UContainer 来承载内容并自动约束最大宽度与水平内边距,因此在定制时通常只需要关注 container 与 root 两个插槽位即可获得完整布局控制。

实现细节与质量保障

底层的组件组合

PageCTA 并非独立实现布局,而是组合了多个底层单元:

  • Primitive(来自 reka-ui 体系,通过 as 透传标签);
  • UContainer:提供响应式容器约束;
  • UButton:links 中的每一项以 size="lg" 渲染,保证按钮在 CTA 语境下的视觉比重;
  • useComponentProps、usePrefix 等 composables 负责全局配置合并与工具类注入。

无障碍保证

PageCTA 的根节点会输出 data-slot="root" 与 data-orientation 属性,标题使用语义化 h2。官方测试 PageCTA.spec.ts 使用 vitest-axe 对包含 title、description、links 的完整 CTA 进行自动无障碍检测,并断言 toHaveNoViolations(),确保默认用法通过 WCAG 扫描。此外测试通过 renderEach 对全部 5 种 variant、9 个插槽以及 as、reverse、orientation、ui 等组合进行快照渲染(PageCTA.spec.ts),为组件的回归稳定性提供了保障。

小结

UPageCTA 是 Nuxt UI v4 页面组件体系中负责「转化收口」的关键组件:一个 root/container/wrapper 三段式结构、9 个灵活插槽、5 种开箱即用的变体,以及基于 tv 的双层主题定制机制。无论是直接放置于页面末尾,还是嵌套在 PageSection 中做通栏 CTA,它都能以最少代码产出结构清晰、语义正确、无障碍合规的高质量转化区块。配合 Button、PageHero 与 PageSection 使用,即可在数分钟内搭建出完整的营销页面骨架。

登录后查看全文
ui