- UI组件
- 前端
【免费下载链接】ng-zorro-antd
Angular UI Component Library based on Ant Design
Affix(固钉)是 ng-zorro-antd 提供的页面固定组件,用于将侧边菜单、操作按钮等元素"钉"在可视范围内,使其在页面滚动时始终保持可见。本文以 components/affix/doc/index.zh-CN.md 官方文档为骨架,结合组件源码、官方 demo 与全局配置实现,系统讲解nz-affix的完整 API、实战用法、全局配置方式以及底层固定位置计算原理。读完本文,你将能够在长页面场景下正确使用 Affix 固定导航与操作区,并理解其"滚动监听 + 占位元素 + 固定定位"的核心工作机制。
何时使用 Affix
当内容区域比较长、需要滚动页面时,这部分内容对应的操作或导航需要在滚动范围内始终展现。Affix 最常见的应用场景是侧边菜单和按钮组合:例如文章详情页侧边的目录导航、长表单页底部的"保存 / 取消"操作按钮、列表页顶部的筛选工具栏等。
需要注意的是:当页面可视范围过小时,慎用此功能,以免固定元素遮挡页面内容。这是官方文档明确给出的使用边界——Affix 不应覆盖页面其他内容,尤其是视口较小时更应谨慎。
快速上手:最简单的用法
在独立组件(standalone)或模块化引入方式下,首先导入NzAffixModule:
import { NzAffixModule } from 'ng-zorro-antd/affix'; import { NzButtonModule } from 'ng-zorro-antd/button';将需要固定的元素包进<nz-affix>即可。参考官方基础示例 components/affix/demo/basic.ts:
<nz-affix [nzOffsetTop]="offsetTop"> <button nz-button nzType="primary" (click)="setOffsetTop()"> <span>Affix top</span> </button> </nz-affix> <br /> <nz-affix [nzOffsetBottom]="nzOffsetBottom" (click)="setOffsetBottom()"> <button nz-button nzType="primary"> <span>Affix bottom</span> </button> </nz-affix>export class NzDemoAffixBasicComponent { offsetTop = 10; nzOffsetBottom = 10; setOffsetTop(): void { this.offsetTop += 10; } setOffsetBottom(): void { this.nzOffsetBottom += 10; } }第一个 Affix 固定于顶部、距顶部10px处触发;第二个固定于底部、距底部10px处触发。点击按钮改变偏移量,可以直观看到固定触发点随偏移值变化。
API 详解:nz-affix 的四个成员
官方文档给出nz-affix的全部 API,整理如下:
| 成员 | 说明 | 类型 | 默认值 | 全局配置 |
|---|---|---|---|---|
[nzOffsetBottom] | 距离窗口底部达到指定偏移量后触发 | number | - | ✅ |
[nzOffsetTop] | 距离窗口顶部达到指定偏移量后触发 | number | 0 | ✅ |
[nzTarget] | 设置nz-affix需要监听其滚动事件的元素,值为一个返回对应 DOM 元素的函数 | string \| HTMLElement | window | |
(nzChange) | 固定状态改变时触发的回调函数 | EventEmitter<boolean> | - |
nzOffsetTop:顶部固定偏移
元素滚动到距离窗口(或nzTarget指定容器)顶部nzOffsetTop像素时触发固定,默认值为0,即元素一到达视口顶部边缘即被固定。
在源码 components/affix/affix.component.ts 中,该输入通过numberAttributeWithZeroFallback转换器处理,并带有@WithConfig()装饰器,说明它支持全局配置覆盖:
@Input({ transform: numberAttributeWithZeroFallback }) @WithConfig() nzOffsetTop?: null | number;nzOffsetBottom:底部固定偏移
当元素滚动到距离窗口底部nzOffsetBottom像素时触发固定,此时元素以position: fixed; bottom: ...的方式贴住视口底部。该参数没有默认值(-),即默认不启用底部固定模式。
注意一个关键的优先级逻辑(见 affix.component.ts):若nzOffsetTop与nzOffsetBottom都未显式设置数值,则默认采用顶部固定模式且offsetTop = 0;只要其中一个被设置为数值,就按显式值进入对应的固定模式。
nzTarget:自定义滚动容器
nzTarget用于设置nz-affix需要监听滚动事件的元素,默认是window。传入值可以是:
- 返回 DOM 元素的函数(文档表述);
- 直接传
HTMLElement或选择器字符串string(源码类型为string | Element | Window,见 affix.component.ts)。
源码中target的解析逻辑(affix.component.ts):
private get target(): Element | Window { const el = this.nzTarget; return (typeof el === 'string' ? this.document.querySelector(el) : el) || window; }即字符串会被当作 CSS 选择器查询,查询失败或未设置时回退到window。当固定发生在非窗口容器中时,底部偏移会额外叠加"窗口高度与容器底部之间"的间距(affix.component.ts):
const targetBottomOffset = targetNode === window ? 0 : window.innerHeight - targetRect.bottom!;nzChange:固定状态改变回调
(nzChange)在固定状态发生切换时触发(从不固定变为固定、或从固定变为不固定),回调参数为布尔值:true表示当前已固定,false表示已解除固定。
源码中该输出通过 Angular 新式output()函数声明(affix.component.ts),并仅在状态真正发生翻转时才 emit(affix.component.ts):
if ((affixStyle && !originalAffixStyle) || (!affixStyle && originalAffixStyle)) { this.nzChange.emit(fixed); }监听固定状态变化
参考官方示例 components/affix/demo/on-change.ts:设置nzOffsetTop为120,即元素滚动到距顶部 120px 时固定,并通过nzChange回调得知当前是否处于固定状态:
<nz-affix [nzOffsetTop]="120" (nzChange)="onChange($event)"> <button nz-button> <span>120px to affix top</span> </button> </nz-affix>export class NzDemoAffixOnChangeComponent { onChange(status: boolean): void { console.log(status); } }该能力非常实用:例如固定后可以给元素追加阴影样式、改变按钮文案,或联动调整页面布局的占位。
在自定义滚动容器内固定(nzTarget 实战)
官方示例 components/affix/demo/target.ts 演示了如何将 Affix 限定在某个可滚动容器内,而不是整个窗口:
<div class="scrollable-container" #target> <div class="background"> <nz-affix [nzTarget]="target" id="affix-container-target"> <button nz-button nzType="primary"> <span>Fixed at the top of container</span> </button> </nz-affix> </div> </div>styles: ` .scrollable-container { height: 100px; overflow-y: scroll; } .background { padding-top: 60px; height: 300px; background-image: url(//zos.alipayobjects.com/rmsportal/RmjwQiJorKyobvI.jpg); } `要点:
- 容器需要设置固定高度与
overflow-y: scroll(或auto),使其成为真正可滚动的区域; - 通过模板引用变量
#target将容器元素传给nzTarget; - 此时 Affix 只监听该容器的滚动事件,容器内部的滚动才会触发固定,页面本身的滚动不会影响它。
全局配置:通过 NzConfig 统一设置偏移
表格中nzOffsetTop与nzOffsetBottom标注了"全局配置 ✅",意味着可以通过 ng-zorro-antd 的全局配置服务统一设置,无需在每个组件实例上重复传入。
全局配置类型定义于 components/core/config/config.ts:
export interface AffixConfig { nzOffsetBottom?: number; nzOffsetTop?: number; }配置方式(例如在app.config.ts中):
import { provideNzConfig } from 'ng-zorro-antd/core/config'; const nzConfig = { affix: { nzOffsetTop: 80, // 全局默认顶部偏移 nzOffsetBottom: 40 // 全局默认底部偏移 } }; export const appConfig: ApplicationConfig = { providers: [provideNzConfig(nzConfig)] };实例上显式传入的nzOffsetTop/nzOffsetBottom会覆盖全局配置(源码中@WithConfig()装饰器即实现"实例值优先、否则回退全局值"的合并逻辑)。
源码级实现原理
要真正驾驭 Affix,理解其底层机制很有帮助。核心逻辑集中在 components/affix/affix.component.ts:
1. 事件监听与节流
组件在构造时通过effect注册监听(affix.component.ts),并借助ngZone.runOutsideAngular将事件处理移出 Angular Zone 以减少不必要的变更检测开销。监听的事件定义于 components/affix/respond-events.ts:
export enum AffixRespondEvents { resize = 'resize', scroll = 'scroll', touchstart = 'touchstart', touchmove = 'touchmove', touchend = 'touchend', pageshow = 'pageshow', load = 'LOAD' }所有事件流与NzResizeObserver观察到的尺寸变化合并后,统一经过throttleTime(20ms)节流(常量NZ_AFFIX_DEFAULT_SCROLL_TIME = 20,见 affix.component.ts),最终驱动updatePosition重算位置。
2. 占位元素与双样式机制
这是 Affix 最精妙的设计:组件模板(affix.component.ts)在内部包了一层<div #fixedEl>来装载投影内容(ng-content),而组件宿主本身充当占位元素:
<div #fixedEl> <ng-content /> </div>- 占位样式(placeholderStyle):当内容被固定(脱离文档流)时,宿主元素会被赋予与固定内容相同的
width与height,从而撑住原布局位置,避免下方内容上跳; - 固定样式(affixStyle):内部
fixedEl被设置为position: fixed并定位到视口(或容器)相应位置,同时添加ant-affix类(常量NZ_AFFIX_CLS_PREFIX,见 affix.component.ts)。
固定时元素的实际定位计算(顶部模式)为(affix.component.ts):
if (scrollTop >= elemOffset.top - (offsetTop as number) && offsetMode.top) { const width = elemOffset.width; const top = targetRect.top + (offsetTop as number); this.setAffixStyle(e, { position: 'fixed', top, left: targetRect.left + elemOffset.left, width }); ... }其中元素相对容器的偏移由工具函数getOffset计算(affix.component.ts),getTargetRect则区分窗口(返回全零矩形)与普通元素(返回getBoundingClientRect()),实现见 components/affix/utils.ts。
3. 与文档一致的行为细节
- 固定/解除固定只改变内部
fixedEl的样式与ant-affix类,不销毁、不重建投影内容; - 方向(RTL/LTR)变化时组件会重新计算位置(构造函数中
effect读取dir()信号); - 滚动事件经过 20ms 节流且带
trailing选项,保证连续滚动时高频位置更新被合并,性能可控。
注意事项与避坑指南
nz-affix内的元素不要使用绝对定位(position: absolute),因为固定定位(fixed)与绝对定位叠加会破坏相对定位基准。如确实需要绝对定位效果,官方文档给出的做法是:直接对nz-affix本身设置绝对定位:
<nz-affix style="position: absolute; top: 10px, left: 10px"> ... </nz-affix>另外两点实践建议:
- 固定元素会脱离文档流,Affix 已通过占位元素保持布局稳定,但请避免在视口过小的场景下使用,防止固定内容遮挡正文;
- 页面中存在横向滚动条时,注意固定元素以
left定位(相对滚动容器左侧),若容器宽度小于元素宽度可能造成截断,必要时结合全局配置调整偏移。
小结
Affix 是长页面场景下提升可用性的基础组件,其核心 API 只有四个:顶部偏移nzOffsetTop(默认 0)、底部偏移nzOffsetBottom、自定义滚动容器nzTarget(默认window)以及固定状态回调nzChange。通过全局配置NzConfig的affix节点可以统一管理前两个偏移参数。从源码看,它依靠"滚动/触摸/尺寸变化事件 + 20ms 节流"驱动位置重算,并用"宿主占位 + 内部 fixed 样式"的双层结构在固定时保持布局稳定——理解这一机制,有助于在复杂布局中正确地使用并排查 Affix 相关的定位问题。
- UI组件
- 前端
【免费下载链接】ng-zorro-antd
Angular UI Component Library based on Ant Design
相关推荐
ng-zorro-antd Affix 固钉组件完全指南:让页面元素吸附视口
ng zorro antd Affix 固钉组件完全指南:让页面元素吸附视口 Affix(固钉)是 ng zorro antd 提供的一个基础布局组件:当用户浏
UI组件前端ng-zorro-antd Collapse 折叠面板组件完全指南:从 API 配置到源码实现剖析
ng zorro antd Collapse 折叠面板组件完全指南:从 API 配置到源码实现剖析 导读 本文是 ng zorro antd 中 Collaps
UI组件前端ng-zorro-antd Affix 组件 nzChange 回调:固定状态监听与源码原理深入解析
ng zorro antd Affix 组件 nzChange 回调:固定状态监听与源码原理深入解析 nz affix (固钉)是 ng zorro antd
UI组件前端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考