- 前端
- UI组件
- 设计系统
【免费下载链接】vue-devui
基于全新 DevUI Design 设计体系的 Vue3 组件库,面向研发工具的开源前端解决方案。
在长文档、帮助中心或研发工具等需要「页内快速导航」的场景中,Anchor 锚点组件通过在页面上建立链接与目标区块的映射关系,实现点击链接平滑滚动到指定位置,并在滚动过程中自动高亮当前所在章节。本文基于 vue-devui 组件库的 Anchor 组件(文档见 packages/devui-vue/docs/components/anchor/index.md),完整讲解其三条指令v-d-anchor-box、v-d-anchor-link、v-d-anchor的用法、参数与激活事件,并结合仓库源码剖析其滚动、高亮与 URL Hash 同步的实现原理,帮助读者在项目里快速落地「目录导航 + 章节定位」功能。
组件概览与何时使用
Anchor 是「跳转到页面指定位置的组件」,属于 vue-devui 导航类(category: '导航')组件。当页面内容较长、需要在各个部分之间实现快速跳转时即可使用,典型场景包括:
- 文档页 / 帮助中心左侧的章节目录
- 长表单分块填写时的步骤导航
- 研发工具中的配置项快速定位
与常规「一个组件 + 一个配置对象」的封装方式不同,vue-devui 的 Anchor 以**指令(directive)**为主要交互载体,由三个指令协作完成全部能力,由 packages/devui-vue/devui/anchor/index.ts 统一注册:
install(app: App): void { app.directive(dAnchor.name, dAnchor); app.directive(dAnchorLink.name, dAnchorLink); app.directive(dAnchorBox.name, dAnchorBox); app.component(Anchor.name, Anchor); }即:全局注册DAnchorBox、DAnchorLink、DAnchor三条指令,同时导出同名Anchor组件(当前Anchor组件本体为占位容器,功能主要由指令承担,组件实现见 anchor.tsx)。
三个指令各司其职:
| 指令 | 职责 |
|---|---|
v-d-anchor-box | 定义扫描锚点的滚动容器,放在dAnchor与dAnchorLink的公共父节点上,负责锚点和链接之间的通信 |
v-d-anchor-link | 定义一个锚点链接,点击后平滑滑动到对应锚点 |
v-d-anchor | 定义一个锚点(章节区块),并参与滚动激活状态的判定 |
基本用法
在页面中使用时,只需要一个容器节点,内部用无序列表承载链接、用普通块级元素承载锚点区块。参考文档示例与 demo.tsx:
<!-- class="scrollTarget" 加上这个类名是局部滚动,不加是全局滚动 --> <div v-d-anchor-box className="scrollTarget"> <ul> <li v-d-anchor-link="anchorlink-one">anchorlink-one</li> <li v-d-anchor-link="anchorlink-two">anchorlink-two</li> <li v-d-anchor-link="anchorlink-three">anchorlink-three</li> <li v-d-anchor-link="anchorlink-four">anchorlink-four</li> </ul> <div> <div v-d-anchor="anchorlink-one"> anchorlink-one1 </div> <div v-d-anchor="anchorlink-two"> anchorlink-two </div> <div v-d-anchor="anchorlink-three"> anchorlink-three </div> <div v-d-anchor="anchorlink-four"> anchorlink-four </div> </div> </div>全局滚动与局部滚动
示例代码中有一处关键注释:容器上添加scrollTarget类名即为局部滚动,不加则为全局滚动。
- 全局滚动:滚动事件绑定在
window上,锚点位置按document.documentElement.scrollTop || document.body.scrollTop计算,适用于整页内容较长、目录固定于一侧的场景; - 局部滚动:滚动事件绑定在容器元素上,按
scrollTarget容器的scrollTop计算,适用于页面内嵌一个独立滚动区域(如面板内长列表)的场景。
从 d-anchor-box.ts 的源码可以看到容器对这两种模式的判定逻辑:
window.onscroll = function () { windoScrollTop = document.documentElement.scrollTop || document.body.scrollTop; if (!document.getElementsByClassName('scrollTarget').length) { // 全局滚动:根据滚动位置切换 sidebar 的定位(absolute/fixed) } else { cssChange(mysidebar, 'absolute', div.scrollTop, 0); } }; // 容器自身的滚动事件 addEvent?.(div, 'scroll', function () { if (document.getElementsByClassName('scrollTarget').length) { cssChange(mysidebar, 'fixed', div.getBoundingClientRect().top, div.getBoundingClientRect().left); } });此外,d-anchor-box挂载时会给容器生成一个随机 id(复用shared/utils中的randomId工具,见 random-id.ts),并追加mycontainer、mymain类名,作为后续侧边导航定位、滚动监听的作用域标识。
Anchor:定义一个锚点
v-d-anchor用于在页面中定义一个锚点(章节区块),是滚动激活判定的目标单元。
Anchor 参数
| 参数 | 类型 | 默认 | 说明 |
|---|---|---|---|
dAnchor | string | -- | 必选,设置一个锚点的名字 |
anchorActive | string | -- | 可选,锚点处于激活状态时,模块生效对应的 CSS 类名 |
源码中的挂载行为
在 d-anchor.ts 中,指令挂载(mounted)时会完成以下动作:
- 若父节点没有类名,则补上
mycontent(右侧内容区样式); - 在元素内部插入一个隐藏的
<a class="box-anchor" href="#锚点名">,作为锚点映射关系中的 Hash 载体,供链接查询与匹配; - 给元素设置
section-block类名,并写入name="锚点名"属性——点击链接时正是通过document.getElementsByName(binding.value)找到目标区块的; - 绑定
onclick,点击锚点区块时通过hightLightFn高亮对应的链接。
mounted(el: HTMLElement, binding: Bind): void { const parent: Element = el.parentNode as Element; if (!parent.className) { parent.className = 'mycontent'; } el.innerHTML = '<a class="box-anchor" style="display:none" href="#' + binding.value + '">?</a>' + el.innerHTML; el.className = 'section-block'; el.setAttribute('name', binding.value); el.onclick = () => { hightLightFn(binding.value); }; }对应的默认样式在 anchor.scss 中定义:.section-block有min-height: 200px与底部虚线分隔,保证每个章节区块有足够的可点击/可判定区域。
Anchor 锚点激活事件
锚点被激活时,组件会自动在锚点元素上添加对应的 CSS 类,用来区分「激活是由什么动作触发的」,便于开发者针对不同触发来源定制样式:
| CSS 类名 | 代表意义 |
|---|---|
anchor-active-by-anchor-link | 点击锚点链接激活 |
anchor-active-by-scroll | 容器滚动到锚点位置激活 |
anchor-active-by-click-inside | 点击锚点内部内容激活 |
anchor-active-by-initial | 初始化滚动条位置激活 |
这些类名配合section-block.active前缀使用。例如 anchor.scss 中内置的「点击链接后区块闪烁高亮」动画即利用了第一类激活:
.section-block.active.anchor-active-by-anchor-link { -webkit-animation: hightlight-and-disapear 3s linear 1; animation: hightlight-and-disapear 3s linear 1; }动画hightlight-and-disapear在 10%~50% 时间点给区块绘制var(--devui-brand, #5e7ce0)的描边并逐渐淡出,实现「定位到目标后短暂高亮提醒」的视觉反馈,主题色通过 DevUI Design 变量接入主题系统。
AnchorLink:定义一个锚点链接
v-d-anchor-link用于定义目录中的链接项,点击后会平滑滑动到对应的锚点区块;当滚动使锚点位于页面顶部附近时,对应链接也会被激活并高亮。
AnchorLink 参数
| 参数 | 类型 | 默认 | 说明 |
|---|---|---|---|
dAnchorLink | string | -- | 必选,点击滑动的目标锚点的名字 |
anchorActive | string | -- | 可选,锚点处于激活状态时,链接生效对应的 CSS 类名 |
源码中的挂载与点击行为
在 d-anchor-link.ts 中,链接项挂载时会:
- 若父节点(通常是
<ul>)没有类名,则补上mysidebar step-nav,使其具备侧边导航的样式与结构约定; - 为链接项设置
bar-link-item类名,并追加隐藏的<a class="d-d-anchor" href="#锚点名">; - 用锚点名作为元素
id,便于滚动激活时通过document.getElementById定位高亮; - 绑定
onclick:先根据页面是否存在scrollTarget决定滚动容器(局部滚动取容器元素、全局滚动取window),再调用scrollToControl执行平滑滚动。
el.onclick = () => { let scrollContainer: IScrollContainer; const scollToDomY = document.getElementsByName(binding.value)[0]; document.getElementsByClassName('scrollTarget').length ? scrollContainer = (document.getElementsByClassName('scrollTarget')[0] as IScrollContainer) : scrollContainer = window as IScrollContainer; scrollToControl(scollToDomY, scrollContainer); };scrollToControl与平滑滚动实现位于 utils.ts:它计算目标区块相对容器的距离,按固定步长(timeoutIntervalSpeed = 10)通过多次setTimeout逐帧scrollBy,形成平滑滚动效果;滚动结束后再通过history.replaceState将当前锚点 Hash 同步到地址栏,并触发对应链接高亮:
function scrollSmoothly(scrollPos: number, repeatTimes: number, container: HTMLElement): void { if (repeatCount <= repeatTimes) { scrollPos > 0 ? container.scrollBy(0, timeoutIntervalSpeed) : container.scrollBy(0, -timeoutIntervalSpeed); } else { repeatCount = 0; clearTimeout(cTimeout); history.replaceState(null, '', document.location.pathname + '#' + hashName); hightLightFn(hashName); ... } repeatCount++; cTimeout = setTimeout(() => { scrollSmoothly(scrollPos, repeatTimes, container); }, 10); }滚动过程中的链接自动高亮
d-anchor-box挂载时会调用setActiveLink(timeId)建立「链接 ↔ 锚点」的映射关系(见 d-anchor-box.ts):
- 通过
.step-nav > li.bar-link-item > a收集当前容器作用域内的全部链接; - 通过
.box-anchor收集页面内全部锚点,并按hash值把链接与锚点一一配对; - 在滚动事件(
onScroll,300ms 节流防抖)触发时,依据当前scrollTop与各锚点位置判断当前应处于哪个章节,命中后history.replaceState更新地址栏 Hash、activateLink高亮对应链接,并向上为父级目录项同步active类。
const onScroll = throttleAndDebounce(setActiveLink, 300);高亮切换统一由hightLightFn完成:先清空侧边栏中所有带active的项,再为当前命中的链接 id 添加active类(见 utils.ts)。默认激活态样式同样定义在 anchor.scss 中——li.active/li:hover时文字变为品牌色var(--devui-brand-active, #526ecc),并通过::before圆形节点和竖线连接线构建出「步骤式」目录的视觉层级。
AnchorBox:锚点通信容器
v-d-anchor-box是锚点功能的前提——必须有一个容器,否则功能无法使用。它必须放置在dAnchor与dAnchorLink的公共父节点上,负责:
- 生成容器唯一 id,并追加
mycontainer/mymain类名作为内部作用域标识; - 监听
window滚动(全局滚动)或容器自身滚动(局部滚动),驱动链接高亮与 Hash 更新; - 根据滚动位置切换侧边导航(
.mysidebar)的定位方式:页面滚动至容器范围内时使用fixed跟随,超出范围后回退为absolute,实现「目录吸顶/随动」效果(对应源码 d-anchor-box.ts 中的cssChange与window.onscroll逻辑); - 监听
window.resize,在窗口尺寸变化时重置侧边导航为absolute定位。
同时,侧边导航的默认宽度为240px(见 anchor.scss 中.mysidebar与.step-nav的定义),内容区.mycontent通过margin-left: 240px与目录形成左右分栏布局。
实践要点与注意事项
- 三个指令必须配套使用:
v-d-anchor-box是链路入口(缺少它则滚动监听与链接匹配无法工作),v-d-anchor-link负责触发,v-d-anchor负责承载与命中判定; - 指令值(锚点名)必须在链接与锚点间一一对应:链接通过
getElementsByName查找目标锚点,锚点通过name属性与隐藏<a>的hash参与匹配,名字不一致将导致滚动定位失败; - 局部滚动记得添加
scrollTarget类名:该类名同时控制滚动容器选取、scrollTop计算方式与侧边导航定位策略;不添加则默认走整页(window)滚动逻辑; - URL Hash 会被同步更新:滚动命中锚点或点击链接后,组件通过
history.replaceState写入#锚点名,不会产生历史记录,便于在刷新/分享后仍能感知当前位置; - 激活态类名是样式定制的扩展点:可依据
anchor-active-by-anchor-link、anchor-active-by-scroll等类名(见上文表格)为不同触发来源编写差异化样式; - 当前实现说明:从 d-anchor.ts 与 d-anchor-link.ts 的
binding接口看,目前源码仅消费value(锚点名),文档中列出的可选参数anchorActive尚未在指令挂载逻辑中体现,使用前建议先在目标环境中验证或自行扩展,且该组件在 index.ts 中标注状态为50%; - 样式依赖主题变量:
anchor.scss大量使用--devui-brand、--devui-brand-active、--devui-text-weak、--devui-line等 DevUI Design 变量(引入自@devui/theme/styles-var/devui-var.scss),使用前需确保项目已接入 devui-theme 主题体系,以保证配色与整体设计语言一致。
综上,vue-devui 的 Anchor 组件以「容器 + 链接 + 锚点」三段式指令模型,覆盖了从点击平滑滚动、滚动激活高亮到 URL Hash 同步的完整页内导航链路;其源码结构清晰、样式挂件独立,既可直接用于文档站与工具类页面的章节导航,也为二次定制(激活类名、侧边栏定位策略、滚动节流等)保留了充足的扩展空间。
- 前端
- UI组件
- 设计系统
【免费下载链接】vue-devui
基于全新 DevUI Design 设计体系的 Vue3 组件库,面向研发工具的开源前端解决方案。
相关推荐
Ant Design锚点组件:Anchor与页面导航实现
Ant Design锚点组件:Anchor与页面导航实现 在现代Web应用开发中,长页面内容的导航体验直接影响用户体验。当用户面对大量信息时,如何快速定位到目标
UI组件前端设计系统Ant Design Vue Anchor 组件完全指南:单页滚动锚点导航的 API 详解与源码剖析
Ant Design Vue Anchor 组件完全指南:单页滚动锚点导航的 API 详解与源码剖析 Anchor 是 Ant Design Vue 中用于在单
前端UI组件设计系统Ant Design Anchor 锚点组件完全指南:API 配置、滚动高亮原理与实战示例
Ant Design Anchor 锚点组件完全指南:API 配置、滚动高亮原理与实战示例 Ant Design 的 Anchor(锚点)组件用于在单页内展示可
前端UI组件设计系统
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考