Nuxt UI v4 FooterColumns 组件实战指南:用数据驱动构建页脚链接列

原创2026-10-07 20:17:06593 阅读
文章标签:前端UI组件

Nuxt UI v4 FooterColumns 组件实战指南:用数据驱动构建页脚链接列

FooterColumns 是 Nuxt UI v4 中用于在页脚区域渲染"多列链接列表"(典型如站点地图、社区链接、产品导航)的导航类组件。本指南将围绕 FooterColumns 官方文档 展开,结合仓库中的 组件源码、主题定义 与 测试用例,系统讲解它的定位、用法、数据模型、插槽体系与主题定制方式。读完本文,你将掌握如何用一份纯数据配置出一套完整、可访问、可深度定制的页脚链接列。

FooterColumns 组件在浅色主题下的渲染效果

FooterColumns 是什么:为页脚而生的链接列容器

从官方文档的定位看,FooterColumns "renders a list of columns to display in your Footer",即渲染一组用于展示在页脚中的链接列。它属于 navigation 类别的组件,关键词包括 footer links、sitemap、columns,是搭建页脚导航(Footer + Sitemap)的常用载体。

在组件层级上,它并不是独立出现的,而是设计为配合 Footer 组件 使用——官方文档明确要求把它放进 Footer 组件的 top 插槽中。这一点在 Footer 源码 中可以看到印证:Footer 会在根节点下渲染 top、bottom 两个插槽区,以及内部的 right、center、left 三个布局区,FooterColumns 正是被设计用来填充 top 区域的。

基础用法:放进 Footer 的 top 插槽

官方文档给出的最小使用方式如下:

<template>
  <UFooter>
    <template #top>
      <UContainer>
        <UFooterColumns />
      </UContainer>
    </template>
  </UFooter>
</template>

要点说明:

  • 组件放在 UFooter 的 #top 插槽内,外部通常再包一层 UContainer 以限制内容宽度、保持与页面上方内容区对齐。
  • 从 Footer 主题 可以看到,top 插槽区默认带有 py-8 lg:py-12 的纵向内边距,因此 FooterColumns 自身无需再关心与页脚的间距问题。
  • FooterColumns 默认渲染为 nav 语义元素(见源码中 withDefaults(..., { as: 'nav' })),符合导航区域的语义化要求,无需额外包裹 <nav>。

用 columns 数据驱动列与链接

FooterColumns 的核心设计是"数据驱动":通过 columns prop 传入结构化的列与链接数据,组件自动完成渲染。

FooterColumn:列的结构

columns 是一个对象数组,每项代表一列,类型定义在 FooterColumns 源码 中:

export interface FooterColumn<T extends FooterColumnLink = FooterColumnLink> {
  label: string
  children?: T[]
}
  • label: string(必填):列标题,渲染为 <h3> 标题元素。
  • children?: FooterColumnLink[]:该列下的链接列表,可选。

FooterColumnLink:链接的结构

children 数组中的每个链接对象,其类型为 FooterColumnLink,支持以下属性:

export interface FooterColumnLink extends Omit<LinkProps, 'custom'> {
  label: string
  icon?: IconProps['name']
  class?: any
  ui?: Partial<Pick<FooterColumns['slots'], 'item' | 'link' | 'linkLabel' | 'linkLabelExternalIcon' | 'linkLeadingIcon'>>
}
  • label: string:链接文案。
  • icon?: string:链接前导图标,使用 Iconify 图标名(源码中以 @IconifyIcon 标注,例如 i-lucide-users)。
  • class?: any:附加到该链接根元素的额外类名。
  • ui?: object:针对单个链接的细粒度样式覆盖,可覆盖 item、link、linkLabel、linkLabelExternalIcon、linkLeadingIcon 五个主题插槽。

透传 Link 组件属性

官方文档特别说明:链接对象可以透传 Link 组件 的任何属性,例如 to、target、href、exact、active、rel、prefetch 等。这是因为 FooterColumnLink 类型本身继承了 Omit<LinkProps, 'custom'>,在渲染时源码通过 pickLinkProps(link) 从数据中精确提取出所有 Link 相关属性再绑定到 ULink 上(见 FooterColumns.vue),不会污染外层容器。

完整可运行示例

将列数据写在 script 中并绑定到组件上:

<script setup lang="ts">
import type { FooterColumn } from '#ui'  // 或从 '@nuxt/ui' 导入类型

const columns: FooterColumn[] = [{
  label: 'Community',
  children: [{
    label: 'Nuxters',
    to: 'https://nuxters.nuxt.com',
    target: '_blank'
  }, {
    label: 'Nuxt on GitHub',
    to: 'https://github.com/nuxt',
    target: '_blank',
    icon: 'i-lucide-github'
  }]
}, {
  label: 'Enterprise',
  children: [
    { label: 'Support' },
    { label: 'Agencies' },
    { label: 'Sponsors' }
  ]
}]
</script>

<template>
  <UFooter>
    <template #top>
      <UContainer>
        <UFooterColumns :columns="columns" />
      </UContainer>
    </template>
  </UFooter>
</template>

上述示例中,没有 to 属性的链接会渲染为纯文本占位项;带有 to 与 target: '_blank' 的链接则具备完整的外部跳转行为。该结构与 测试用例 中构造的 Community / Enterprise / Solutions 三列数据模型完全一致,可以直接对照参考。

外部链接自动识别与 external 图标

一个值得注意的细节是:当链接的 target === '_blank' 时,组件会自动在链接文案尾部渲染一个"外部链接"小图标,提示用户该链接将在新窗口打开。相关逻辑位于 FooterColumns.vue:

<UIcon v-if="link.target === '_blank'" :name="appConfig.ui.icons.external" data-slot="linkLabelExternalIcon" ... />
  • 图标名称取自全局 appConfig.ui.icons.external 配置,而非硬编码,因此你可以在应用配置中全局替换该图标。
  • 该图标通过 linkLabelExternalIcon 主题插槽控制样式,默认渲染为右上角 size-3 的小图标(见 footer-columns.ts)。

插槽体系:从整体布局到单个链接的全面可定制

FooterColumns 提供了丰富的插槽体系,类型定义在源码 FooterColumnsSlots 中,可实现从整体布局到单个链接的逐级定制:

插槽 作用 插槽参数(slot props)
left 左侧区域,独立于列之外(如品牌区) 无
default 中心区域,默认渲染所有列;提供后可完全替换列渲染 无
right 右侧区域(如订阅表单、社交按钮) 无
column-label 自定义单列标题 { column: FooterColumn<T> }
link 完全自定义单个链接的整体渲染 { link, active, ui }
link-leading 自定义链接前导内容(默认放图标) { link, active, ui }
link-label 自定义链接文案部分 { link, active }
link-trailing 自定义链接尾部内容 { link, active }

其中 active 表示当前链接是否与当前路由匹配(由内部 ULink 计算并透出),可用于实现"当前页面高亮"等交互效果。ui 参数则是合并后的主题对象,方便在插槽内继续复用主题类名。

一个实际应用是:在 right 插槽中放置订阅表单、在 column-label 中给特定列加徽标,仓库中的 FooterColumnsExample.vue 就演示了 right 插槽的用法(见下文完整示例)。

主题定制:slots 与 variants

默认主题结构

FooterColumns 的默认样式定义在 src/theme/footer-columns.ts,共包含 10 个插槽(slot)与一组 active 变体:

插槽 默认类 作用
root xl:grid xl:grid-cols-3 xl:gap-8 根容器,大屏下三栏网格
left mb-10 xl:mb-0 左侧区域
center flex flex-col lg:grid grid-flow-col auto-cols-fr gap-8 xl:col-span-2 列区域,移动端纵向堆叠、桌面端横向等分布局
right mt-10 xl:mt-0 右侧区域
label text-sm font-semibold 列标题 <h3>
list mt-6 space-y-4 链接列表 <ul>,垂直间距
item relative 每个链接项 <li>
link group text-sm flex items-center gap-1.5 rounded-sm outline-primary/25 focus-visible:outline-3 链接本体,含键盘焦点可见性样式
linkLeadingIcon size-5 shrink-0 前导图标
linkLabel truncate 链接文案,超长截断
linkLabelExternalIcon size-3 absolute top-0 text-dimmed inline-block 外部链接图标

active 变体

当链接匹配当前路由(active 为 true)时:

  • active: true → link 变为 text-primary font-medium(主题色加粗);
  • active: false → link 变为 text-muted hover:text-default,并在启用 theme.transitions 时附加 transition-colors 过渡效果。

这一行为与 Link 组件源码 的激活状态计算机制一致:FooterColumns 内部通过 ULink 的 custom 模式拿到 active 状态,再把它传给 ui.link({ active }) 驱动变体切换。

定制方式

与 Nuxt UI 其他组件一致,FooterColumns 支持两种主题覆盖方式:

  1. 全局配置:在 app.config.ts 中通过 ui.footerColumns 覆盖任意插槽或变体(源码通过 useComponentProps 与 useAppConfig 自动合并,见 FooterColumns.vue)。
  2. 组件级:通过 ui prop 覆盖,例如 ui="{ list: 'lg:gap-1.5' }"(测试用例中即有此用法)。
  3. 单链接级:通过链接对象中的 ui 属性覆盖(上文已介绍)。

源码实现解析:数据如何变成 DOM

从 FooterColumns.vue 的模板可以还原出它的渲染链路:

Primitive(:as="props.as")  →  默认 <nav>
├── left 区域(存在 #left 插槽时渲染)
├── center 区域
│   ├── 默认插槽内容
│   │   └── 每个 column:<h3> 标题 + <ul>
│   │       └── 每个 link:ULink(custom) → ULinkBase
│   │           ├── link-leading(默认渲染 UIcon)
│   │           ├── link-label(文案 + 外部链接图标)
│   │           └── link-trailing
└── right 区域(存在 #right 插槽时渲染)

几个值得注意的实现细节:

  • 组件根节点使用 Reka UI 的 Primitive,as prop 默认值为 'nav',可切换为 'section'、'div' 等任意元素或组件(测试用例 with as 即验证了 as: 'section' 场景)。
  • 链接渲染采用 ULink 的 custom 模式 + ULinkBase 组合:ULink 负责路由匹配、预取(prefetch)、rel/target 处理,ULinkBase 负责实际的元素与样式输出。这意味着页脚链接继承了 Link 组件 的全部能力,如内部/外部链接自动识别、激活态计算、i18n locale 路径等。
  • pickLinkProps(link) 保证只有 Link 相关属性被透传,数据中携带的 class、ui 则单独消费,避免属性冲突。

可访问性与测试保障

FooterColumns 的可访问性是有测试背书的。在 test/components/FooterColumns.spec.ts 中:

  • 组件以 axe 进行无障碍审计,toHaveNoViolations() 断言通过;
  • 通过 renderEach 对全部 props(columns、as、class、ui)与全部插槽(left、default、right、column-label、link、link-leading、link-label、link-trailing)逐一渲染快照,覆盖了本指南介绍的所有 API 面。

语义层面,列标题使用 <h3>、列表使用 <ul>/<li>、外层为 <nav>,默认就具备良好的文档结构与屏幕阅读器体验;链接的 focus-visible:outline-3 样式也保证了键盘可达性。

实战示例:页脚 + 多列导航 + 订阅表单

将上述能力组合起来,即可得到官网同款的页脚结构——三列导航数据 + 右侧订阅表单(参考仓库中的 FooterColumnsExample.vue):

<script setup lang="ts">
import type { FooterColumn } from '#ui'

const columns: FooterColumn[] = [{
  label: 'Community',
  children: [{
    label: 'Nuxters',
    to: 'https://nuxters.nuxt.com',
    target: '_blank'
  }, {
    label: 'Video Courses',
    to: 'https://masteringnuxt.com/nuxt3?ref=nuxt',
    target: '_blank'
  }, {
    label: 'Nuxt on GitHub',
    to: 'https://github.com/nuxt',
    target: '_blank'
  }]
}, {
  label: 'Solutions',
  children: [{
    label: 'Nuxt Content',
    to: 'https://content.nuxt.com/',
    target: '_blank'
  }, {
    label: 'Nuxt DevTools',
    to: 'https://devtools.nuxt.com/',
    target: '_blank'
  }, {
    label: 'Nuxt Image',
    to: 'https://image.nuxt.com/',
    target: '_blank'
  }, {
    label: 'Nuxt UI',
    to: 'https://ui.nuxt.com/',
    target: '_blank'
  }]
}]
</script>

<template>
  <UFooter>
    <template #top>
      <UContainer>
        <UFooterColumns :columns="columns">
          <template #right>
            <UFormField name="email" label="Subscribe to our newsletter" size="lg">
              <UInput type="email" class="w-full">
                <template #trailing>
                  <UButton type="submit" size="xs" color="neutral" label="Subscribe" />
                </template>
              </UInput>
            </UFormField>
          </template>
        </UFooterColumns>
      </UContainer>
    </template>
  </UFooter>
</template>

这个示例覆盖了本指南的全部知识点:columns 数据驱动、target="_blank" 外部链接与自动 external 图标、right 插槽扩展订阅表单,以及 UFooter + UContainer 的标准组合。将这份模板稍作修改即可接入你自己的站点地图与导航数据,快速搭建出专业、可访问、可深度定制的页脚区域。

登录后查看全文
ui