Nuxt UI v4 PageCTA 组件实战指南:用 UPageCTA 构建高质量的页面转化区
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,支持两种覆盖层级:
- 组件级
uiprop:例如: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)。 - 应用级
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 使用,即可在数分钟内搭建出完整的营销页面骨架。