ant-design-vue Anchor 锚点组件完全指南:配置、事件与源码原理
2026/9/20 14:06:48 网站建设 项目流程
  • 前端
  • UI组件
  • 设计系统

【免费下载链接】ant-design-vue

🌈 An enterprise-class UI components based on Ant Design and Vue. 🐜

项目地址:https://gitcode.com/gh_mirrors/an/ant-design-vue
点击查看免费下载

本文围绕 ant-design-vue 官方文档中 Anchor 锚点组件的使用说明展开,系统讲解它的核心用途、全部 Props/事件/AnchorItem 配置、数据化items与嵌套子链接用法、以及如何基于仓库源码理解其高亮与滚动跳转的底层实现。读完本文,你将能够在 Vue 3 项目中快速落地一个支持固定定位、自定义高亮、横向导航和滚动偏移控制的企业级锚点导航。

组件定位与适用场景

Anchor(锚点)用于跳转到页面指定位置:它会在页面上渲染一组可点击的锚点链接,点击后页面平滑滚动到对应的目标区块,并随滚动自动高亮当前所处的章节。ant-design-vue 文档给出的“何时使用”标准是:需要展现当前页面上可供跳转的锚点链接,以及快速在锚点之间跳转

典型应用场景包括:

  • 长文档/帮助中心页面的章节目录(如本仓库中components/anchor/index.zh-CN.md这类 API 文档的侧边导航);
  • 表单、详情页等长页面的分段导航;
  • 教程类站点的内容大纲与进度指示。

组件完整源码位于 components/anchor/Anchor.tsx,入口聚合在 components/anchor/index.tsx(挂载为AnchorAnchor.Link两个组件),测试用例可参考 components/anchor/tests/Anchor.test.js。

基础用法:数据化 items 配置

从 4.0 版本开始,Anchor 推荐使用items数据化配置选项内容,支持通过children进行嵌套。以仓库中 components/anchor/demo/basic.vue 的最简示例为蓝本:

<template> <a-anchor :items="[ { key: 'part-1', href: '#part-1', title: () => h('span', { style: 'color: red' }, 'Part 1'), }, { key: 'part-2', href: '#part-2', title: 'Part 2', }, { key: 'part-3', href: '#part-3', title: 'Part 3', }, ]" /> </template> <script lang="ts" setup> import { h } from 'vue'; </script>

要点说明:

  • 每个 item 的href必须以#开头并指向页面中真实存在的元素id(如#part-1对应<div id="part-1">);
  • title既可以是纯字符串,也可以是函数,函数接收当前 item 并返回 VueNode,可用于渲染富文本标题;
  • key是唯一标志,用于 Vue 的列表 diff 与嵌套结构稳定渲染。

items的结构化渲染在源码 components/anchor/Anchor.tsx 的createNestedLink中实现:它遍历items数组,把children递归地继续生成为嵌套的AnchorLink,并在direction === 'vertical'(垂直)时才渲染子级,水平方向不支持嵌套(详见下文)。

传统写法:Anchor + Link 组合(已弃用)

items引入之前,官方写法是组合AnchorLink子组件,例如:

<template> <a-anchor> <a-link href="#part-1" title="Part 1" /> <a-link href="#part-2" title="Part 2"> <a-link href="#part-2-1" title="Part 2-1" /> </a-link> </a-anchor> </template>

源码 components/anchor/Anchor.tsx 在非生产环境会输出开发警告:

Anchor childrenis deprecated. Please useitemsinstead.

即:Anchor的默认插槽(children)写法已废弃,请改用itemsLink的独立实现见 components/anchor/AnchorLink.tsx,其href默认值为'#',通过registerLink/unregisterLink与父级 Anchor 通信(context 定义于 components/anchor/context.ts)。

Anchor Props 完整参数表

成员说明类型默认值版本
affix固定模式booleantrue
bounds锚点区域边界number5(px)
getContainer指定滚动的容器() => HTMLElement() => window
getCurrentAnchor自定义高亮的锚点(activeLink: string) => string-activeLink(3.3)
offsetBottom距离窗口底部达到指定偏移量后触发number
offsetTop距离窗口顶部达到指定偏移量后触发number
showInkInFixed:affix="false"时是否显示小方块booleanfalse
targetOffset锚点滚动偏移量,默认与 offsetTop 相同numberoffsetTop1.5.0
wrapperClass容器的类名string-
wrapperStyle容器样式object-
items数据化配置选项内容,支持通过 children 嵌套{ key, href, title, target, children }[]-4.0
direction设置导航方向vertical|horizontalvertical4.0
customTitle使用插槽自定义选项 titlev-slot="AnchorItem"-4.0

参数定义可以在源码 components/anchor/Anchor.tsx 的anchorProps()中找到对应实现,下面结合实现逐项深入说明。

affix 与 offsetTop / offsetBottom:固定模式

  • affix默认true,即默认启用固定定位:渲染时 Anchor 会被包裹在Affix组件内(源码中!affix ? anchorContent : <Affix offsetTop={offsetTop} target={getContainer.value}>),吸附在页面顶部不随滚动移出视口;
  • offsetTop表示锚点距离窗口顶部达到指定偏移量后触发固定;offsetBottom表示距离窗口底部达到指定偏移量后触发固定,二者与Affix的语义一致;
  • affix={false}时,Anchor 不浮动,状态也不随页面滚动变化(对应仓库示例 components/anchor/demo/static.vue 的“静态位置”用法)。

值得注意的细节:源码中当设置了offsetTop时,容器会被加上maxHeight: calc(100vh - ${offsetTop}px)的样式约束,避免固定后内容超出视口高度。

bounds 与 getCurrentAnchor:高亮判定与自定义高亮

  • bounds默认 5(px),指锚点区域边界:目标区块顶部进入视口(滚动容器)内offsetTop + bounds范围内即视为“当前区块”。源码getCurrentAnchor中判定条件为top < offsetTop + bounds,并在所有满足条件的 section 中取top最大者作为当前激活链接;
  • getCurrentAnchor允许自定义高亮的锚点,接收内部计算出的activeLink作为参数并返回最终要高亮的链接(3.3 版本起回调参数可用)。仓库示例 components/anchor/demo/customizeHighlight.vue 演示了强制高亮固定链接:
<template> <a-anchor :affix="false" :get-current-anchor="getCurrentAnchor" :items="[...]" ></a-anchor> </template> <script lang="ts" setup> const getCurrentAnchor = () => { return '#components-anchor-demo-static'; }; </script>

对应实现位于 components/anchor/Anchor.tsx 的setCurrentActiveLink:当传入getCurrentAnchor函数时,激活链接会改写为该函数的返回值。

getContainer:指定滚动容器

默认滚动容器是window,当锚点应用于页面内部某个可滚动区域时,通过getContainer返回该容器元素。源码中容器的解析优先级为:

props.getContainer || config-provider 注入的 getTargetContainer || () => window

(见 components/anchor/Anchor.tsx 的getContainercomputed)。同时onUpdated中会对比容器是否变化,若变化则重新绑定scroll事件监听并立即计算一次激活链接。

showInkInFixed:静态模式下的指示小方块

showInkInFixed默认false。当affix={false}时,Anchor 默认不显示左侧/顶部的指示小方块(ink);设置为true可以强制显示。注意源码中锚点容器类名有一个细节:${pre}-fixed仅在!affix && !showInkInFixed时添加,即静态且不显示小方块时才标记为 fixed 布局。

targetOffset:锚点滚动偏移量(1.5.0+)

targetOffset用于设置点击锚点后的目标滚动偏移量,默认与offsetTop相同。它决定了滚动后目标区块停留在视口中的位置——例如希望章节标题滚动到屏幕正中间,可将targetOffset设为视口高度的一半。仓库示例 components/anchor/demo/targetOffset.vue 的用法:

<template> <a-anchor :target-offset="targetOffset" :items="[...]" ></a-anchor> </template> <script lang="ts" setup> import { onMounted, ref } from 'vue'; const targetOffset = ref<number | undefined>(undefined); onMounted(() => { targetOffset.value = window.innerHeight / 2; }); </script>

在源码handleScrollTo中,滚动目标y的计算为:y = scrollTop + eleOffsetTop - (targetOffset !== undefined ? targetOffset : offsetTop || 0),可见targetOffset优先级高于offsetTop

wrapperClass / wrapperStyle:容器定制

  • wrapperClass:容器的自定义类名(string);
  • wrapperStyle:容器的自定义样式(object),会与默认的maxHeight计算值合并(用户传入样式优先级更高)。

direction:垂直 / 水平导航(4.0+)

direction支持vertical(默认)与horizontal两种导航方向。横向模式下锚点链接在一行内水平排列,指示小方块变为水平滑动条,并通过scrollIntoView让激活项保持在可视范围内(见 components/anchor/Anchor.tsx 的updateInk)。仓库示例 components/anchor/demo/horizontal.vue:

<a-anchor direction="horizontal" :items="[ { key: 'horizontally-part-1', href: '#horizontally-part-1', title: 'Part 1' }, { key: 'horizontally-part-2', href: '#horizontally-part-2', title: 'Part 2' }, // ...更多项 ]" />

限制:横向模式下items不支持children嵌套。源码在开发环境会输出警告:

Anchor items#childrenis not supported whenAnchordirection is horizontal.

同时createNestedLink中只有direction === 'vertical'时才递归渲染children

customTitle:插槽自定义标题(4.0+)

customTitle是一个作用域插槽,槽内会注入当前AnchorItem对象,用于完全自定义每个链接的标题渲染,例如加入图标、徽标等复杂结构:

<template> <a-anchor :items="items"> <template #customTitle="{ href, title }"> <span> <my-icon /> {{ title }} </span> </template> </a-anchor> </template>

对应实现:Anchor会把customTitle插槽透传给每一个AnchorLink(见 components/anchor/Anchor.tsx 的createNestedLink与 components/anchor/AnchorLink.tsx 中slots.customTitle(customTitleProps)的调用)。

AnchorItem 数据结构

items中的每一项(AnchorItem)字段如下:

成员说明类型默认值版本
key唯一标志string | number-
href锚点链接string-
target该属性指定在何处显示链接的资源string-
title文字内容VueNode \| (item: AnchorItem) => VueNode-
children嵌套的 Anchor Link,注意:水平方向该属性不支持AnchorItem[]-

类型定义在源码 components/anchor/AnchorLink.tsx 的AnchorLinkItemProps接口中(keyhreftargettitlechildren,并额外支持classstyle)。title为函数时,源码会以当前 item 为参数调用title(customTitleProps)得到渲染节点。

嵌套示例(参考 components/anchor/demo/onChange.vue):

<a-anchor :affix="false" :items="[ { key: '1', href: '#components-anchor-demo-basic', title: 'Basic demo', }, { key: '3', href: '#api', title: 'API', children: [ { key: '4', href: '#anchor-props', title: 'Anchor Props' }, { key: '5', href: '#link-props', title: 'Link Props' }, ], }, ]" />

事件(Events)

事件名称说明回调参数版本
change监听锚点链接改变(currentActiveLink: string) => void1.5.0
clickclick事件的 handlerFunction(e: MouseEvent, link: Object)

change:监听锚点链接改变

滚动经过不同区块或点击链接时触发,回调参数为当前激活的锚点链接字符串。示例(components/anchor/demo/onChange.vue):

<template> <a-anchor :affix="false" :items="items" @change="onChange" /> </template> <script lang="ts" setup> const onChange = (link: string) => { console.log('Anchor:OnChange', link); }; </script>

源码中setCurrentActiveLink在激活链接变化时通过emit('change', link)发出该事件,因此仅在激活链接真正变化时触发。

click:自定义点击行为

点击锚点链接时触发,回调参数为(e: MouseEvent, link: Object),其中link包含{ title, href }。通过e.preventDefault()可以阻止默认跳转/记录历史。示例(components/anchor/demo/onClick.vue):

<template> <a-anchor :affix="false" :items="items" @click="handleClick" /> </template> <script lang="ts" setup> import type { AnchorProps } from 'ant-design-vue'; const handleClick: AnchorProps['onClick'] = (e, link) => { e.preventDefault(); console.log(link); }; </script>

事件派发链路:AnchorLink内点击<a>时调用contextHandleClick(e, { title: mergedTitle, href })并继续scrollTo(href)(见 components/anchor/AnchorLink.tsx),父级 Anchor 的 context 收到后emit('click', e, info)(见 components/anchor/Anchor.tsx 的useProvideAnchor)。

Link Props(传统子组件)

若仍使用传统Anchor.Link写法,其 Props 如下:

成员说明类型默认值版本
href锚点链接string#
target该属性指定在何处显示链接的资源string1.5.0
title文字内容string | slot

href默认值'#'定义于 components/anchor/AnchorLink.tsx 的initDefaultProps(anchorLinkProps(), { href: '#' })title同时支持属性传值与具名插槽#titletarget直接透传到渲染出的<a>标签上(_blank等值)。

源码级原理:锚点如何工作

链接注册与激活高亮

Anchor 通过 Vue 3 的provide / inject(components/anchor/context.ts)向所有AnchorLink提供registerLink/unregisterLink/activeLink/scrollTo/handleClick/direction。每个AnchorLink挂载时注册自己的href,卸载或href变化时注销旧值并注册新值(watch 逻辑见 components/anchor/AnchorLink.tsx),父级维护links数组。

激活高亮的核心流程(components/anchor/Anchor.tsx):

  1. 组件挂载后监听滚动容器的scroll事件(addEventListener(container, 'scroll', handleScroll));
  2. 滚动时遍历所有注册链接,用正则/#([\S ]+)$/提取href中的元素 id;
  3. 通过getElementById找到目标元素,计算其相对滚动容器的top
  4. 收集所有top < offsetTop + bounds的链接,取top最大者作为当前激活链接;
  5. setCurrentActiveLink更新activeLink,激活的AnchorLink渲染-link-active样式类,指示小方块(ink)通过updateInk移动到对应位置。

点击跳转与平滑滚动

点击链接时,handleScrollTo(components/anchor/Anchor.tsx)计算目标滚动位置y = 当前滚动高度 + 元素相对偏移 - (targetOffset ?? offsetTop ?? 0),然后调用scrollTo工具进行平滑滚动。该工具实现在 components/_util/scrollTo.ts:基于requestAnimationFrameeaseInOutCubic缓动函数,默认动画时长450ms,滚动期间animating置为true,从而在滚动过程中忽略滚动事件、避免高亮抖动。

测试验证

components/anchor/tests/Anchor.test.js 覆盖了渲染、点击、onChange回调以及完整 URL(如http://www.example.com/#api)等场景,验证了带完整前缀的链接同样能被解析与高亮;components/anchor/tests/demo.test.js 与快照则保证各 demo 可正常渲染。样式入口位于 components/anchor/style/index.ts。

常见问题与使用建议

  1. 链接没有高亮/点击无反应:检查href指向的元素id是否真实存在,且href#开头;滚动容器必须是getContainer指定的那个容器。
  2. 固定模式下被遮挡:合理设置offsetTop(并让targetOffset保持一致或按需调整),保证高亮判定与最终落点一致。
  3. 页面有固定 HeadertargetOffset应不小于 Header 高度,否则锚点目标会被 Header 遮住。
  4. 横向导航不要用children:源码会在开发环境给出告警,且子级不会被渲染。
  5. 避免混用新旧写法Anchor的默认插槽(children)已标记废弃,新代码一律使用items+customTitle
  6. 页面锚点目标位于自定义滚动容器内:务必通过getContainer显式指定容器,否则组件监听的是window滚动,无法正确计算位置。

以上配置项与事件均可对照 components/anchor/index.en-US.md 及仓库内各 demo 用例(components/anchor/demo/)进行二次验证与扩展实践。

  • 前端
  • UI组件
  • 设计系统

【免费下载链接】ant-design-vue

🌈 An enterprise-class UI components based on Ant Design and Vue. 🐜

项目地址:https://gitcode.com/gh_mirrors/an/ant-design-vue
点击查看免费下载

相关推荐

上一篇:NocoBase 区块高度配置全指南:默认高度、指定高度与全高模式原理详解
下一篇:MetaFormer架构核心解密:convformer_b36.sail_in22k代码实现原理

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询