antd源码-Affix固钉解析

固钉其实按照我自己的理解就是用固定定位将其定位到某个位置。很简单的一个效果。

antd-affix我认为其核心可以概括为几点:

  1. 组件加载滚动监听,组件销毁销毁监听。

  2. 利用一个元素在原本元素位置占位。当达到固定元素的条件。元素占位,反之。相反。

  3. 监听占位元素、宽度高度样式的更改,有更改就去重置渲染参数条件。

render函数

  render() {const { affixStyle, placeholderStyle } = this.state;console.log("affixStyle",this.state)let props = omit(this.props, ['offsetTop', 'offsetBottom', 'target', 'onChange']);const {children,className}=this.props;const AffixclassName = classNames({ 'ant-affix':affixStyle},className);return (<ResizeObserveronResize={() => {this.updatePosition();}}><div ref={this.savePlaceholderNode}>{affixStyle && <div style={placeholderStyle} aria-hidden="true" />}<div className={AffixclassName} ref={this.saveFixedNode}  style={affixStyle}><ResizeObserveronResize={() => {this.updatePosition();}}>{children}</ResizeObserver></div></div></ResizeObserver>)}prepareMeasure = () => {// event param is used before. Keep compatible ts define here.this.setState({status: AffixStatus.Prepare,affixStyle: undefined,placeholderStyle: undefined,});};updatePosition() {this.prepareMeasure();}

从这段代码可以看到的是引用了ResizeObserver,这个组件的功能就是在改变宽度和高度的时候,会触发,做的事情就很简单,初始化状态和固定样式和占位样式,页面的元素就恢复到最初了。

在看初始化做了什么

    componentDidMount(){const { target } = this.props;console.log(target)if (target) {// [Legacy] Wait for parent component ref has its value.// We should use target as directly element instead of function which makes element check hard.// this.timeout = setTimeout(() => {addObserveTarget(target(), this);// Mock Event object.this.updatePosition();});}}componentDidUpdate(prevProps:AffixProps){const { prevTarget } = this.state;const { target } = this.props;let newTarget = null;if (target) {newTarget = target() || null;}if (prevTarget !== newTarget) {removeObserveTarget(this);if (newTarget) {addObserveTarget(newTarget, this);// Mock Event object.this.updatePosition();}this.setState({ prevTarget: newTarget });}if (prevProps.offsetTop !== this.props.offsetTop ||prevProps.offsetBottom !== this.props.offsetBottom) {this.updatePosition();}this.measure();}lazyUpdatePosition() {const { target } = this.props;const { affixStyle } = this.state;// Check position change before measure to make Safari smoothif (target && affixStyle) {const offsetTop = this.getOffsetTop();const offsetBottom = this.getOffsetBottom();const targetNode = target();if (targetNode && this.placeholderNode) {const targetRect = getTargetRect(targetNode);const placeholderReact = getTargetRect(this.placeholderNode);const fixedTop = getFixedTop(placeholderReact, targetRect, offsetTop);const fixedBottom = getFixedBottom(placeholderReact, targetRect, offsetBottom);if ((fixedTop !== undefined && affixStyle.top === fixedTop) ||(fixedBottom !== undefined && affixStyle.bottom === fixedBottom)) {return;}}}// Directly call prepare measure since it's already throttled.this.prepareMeasure();}
  1. 页面加载创建了一个定时器并且在window上添加了一个滚动监听事件addObserveTarget

  2. addObserveTarget函数内部,调用了当前组件的lazyUpdatePosition,去计算出fixedtop的值是否达到offsetTop,达到了就直接返回。没达到就重置。

  3. 而this.setState操作都会牵动componentDIdMount执行。最后都会去执行 this.measure();

measure

 measure = () => {const { status, lastAffix } = this.state;const { target, onChange } = this.props;if (status !== AffixStatus.Prepare || !this.fixedNode || !this.placeholderNode || !target) {return;}const offsetTop = this.getOffsetTop();const offsetBottom = this.getOffsetBottom();const targetNode = target();if (!targetNode) {return;}const newState: Partial<AffixState> = {status: AffixStatus.None,};const targetRect = getTargetRect(targetNode);const placeholderReact = getTargetRect(this.placeholderNode);const fixedTop = getFixedTop(placeholderReact, targetRect, offsetTop);const fixedBottom = getFixedBottom(placeholderReact, targetRect, offsetBottom);if (fixedTop !== undefined) {newState.affixStyle = {position: 'fixed',top: fixedTop,width: placeholderReact.width,height: placeholderReact.height,};newState.placeholderStyle = {width: placeholderReact.width,height: placeholderReact.height,};} else if (fixedBottom !== undefined) {newState.affixStyle = {position: 'fixed',bottom: fixedBottom,width: placeholderReact.width,height: placeholderReact.height,};newState.placeholderStyle = {width: placeholderReact.width,height: placeholderReact.height,};}newState.lastAffix = !!newState.affixStyle;if (onChange && lastAffix !== newState.lastAffix) {onChange(newState.lastAffix);}this.setState(newState as AffixState);};
export function getTargetRect(target: BindElement): ClientRect {return target !== window? (target as HTMLElement).getBoundingClientRect(): ({ top: 0, bottom: window.innerHeight } as ClientRect);
}export function getFixedTop(placeholderReact: Rect,targetRect: Rect,offsetTop: number | undefined,
) {if (offsetTop !== undefined && targetRect.top > placeholderReact.top - offsetTop) {return offsetTop + targetRect.top;}return undefined;
}

拿我们传递了offsetTop=20举例,

  • getTargetRect 这个函数传递window的话。永远top为0,bottom为window的高,传递的是dom元素的话,getBoundingClientRect会返回这个元素的宽高位置信息,
  • 关注getFixedTop,我们没有指定target的时候,targetRect为window,,top永远为0,placeholderReact为占位元素,他的top为初始化元素的top,offsetTop是我们传递的,得到是undefined就初始化,否则继续保持为固定。

antd源码-Affix固钉解析相关推荐

  1. antd学习之Affix固钉的学习

    Affix的学习 这个组件有四个属性值,当我们的页面过长我们需要对某些元素进行固钉在某个位置不再进行跟着父级容器进行滚动时候使用 offsetTop={200}属性是当下拉页面的时候距离顶部200的时 ...

  2. antd源码-spin解析

    antd源码-spin解析 spin的作用是代表当前块正在加载中 Spin 元素的渲染 renderSpin = ({ getPrefixCls }: ConfigConsumerProps) =&g ...

  3. React学习day14--antd:Space间距、Affix固钉

    Space间距 设置组件之间的间距,避免组件紧贴在一起,拉开统一的空间.适合行内元素的水平间距,可以设置各种水平对齐方式. import { Button, Space, Upload, Popcon ...

  4. MyBatis 源码分析 - 映射文件解析过程

    1.简介 在上一篇文章中,我详细分析了 MyBatis 配置文件的解析过程.由于上一篇文章的篇幅比较大,加之映射文件解析过程也比较复杂的原因.所以我将映射文件解析过程的分析内容从上一篇文章中抽取出来, ...

  5. 【flink】Flink 1.12.2 源码浅析 : yarn-per-job模式解析 TaskMasger 启动

    1.概述 转载:Flink 1.12.2 源码浅析 : yarn-per-job模式解析 [四] 上一篇: [flink]Flink 1.12.2 源码浅析 : yarn-per-job模式解析 Jo ...

  6. 【flink】Flink 1.12.2 源码浅析 : yarn-per-job模式解析 JobMasger启动 YarnJobClusterEntrypoint

    1.概述 转载:Flink 1.12.2 源码浅析 : yarn-per-job模式解析 [三] 上一章:[flink]Flink 1.12.2 源码浅析 : yarn-per-job模式解析 yar ...

  7. 【flink】Flink 1.12.2 源码浅析 : yarn-per-job模式解析 yarn 提交过程解析

    1.概述 转载:Flink 1.12.2 源码浅析 : yarn-per-job模式解析 [二] 请大家看原文去. 接上文Flink 1.12.2 源码分析 : yarn-per-job模式浅析 [一 ...

  8. 【flink】Flink 1.12.2 源码浅析 : yarn-per-job模式解析 从脚本到主类

    1.概述 转载:Flink 1.12.2 源码浅析 : yarn-per-job模式解析 [一] 可以去看原文.这里是补充专栏.请看原文 2. 前言 主要针对yarn-per-job模式进行代码分析. ...

  9. Android Fragment 从源码的角度去解析(上)

    ###1.概述 本来想着昨天星期五可以早点休息,今天可以早点起来跑步,可没想到事情那么的多,晚上有人问我主页怎么做到点击才去加载Fragment数据,而不是一进入主页就去加载所有的数据,在这里自己就对 ...

最新文章

  1. 【Bug档案01】Spring Boot的控制器+thymeleaf模板 -使用中出现静态资源加载路径不当的问题 -解决时间:3h
  2. 【转载】linux服务器下非root权限安装anaconda
  3. c++面试题之标准模板库
  4. python决策树算法代码_Python3.0 实现决策树算法的流程
  5. 【教程】Linux 下软 RAID 实现方案!!
  6. 第一阶段_第一部分_工具介绍
  7. python中那纠结的os.system()与空格处理
  8. php实现文本替换,php文本替换 函数 strtr()、str_repalce()
  9. python代码性能分析_Python 性能分析入门指南
  10. SVD(6.5.1定理证明观察3)
  11. python学习——正则表达式
  12. 手机型号大全_2000-2500元智能手机最全导购推荐(学生党手机必看)-2020年12月更新...
  13. 工厂模式的三张类图(一目了然)
  14. 阿里云来担保商标注册申请,担保有哪些程序(详细教程)
  15. matlab图无线型,如何使用MATLAB进行移动无线信道模型的建模资料概述
  16. Cash-Secured Puts Vs. Covered Calls
  17. 小蘑菇也有很大力量,他通过种植蘑菇致富,如何成功?
  18. 郑州各个大学计算机专业分数线,2019年郑州大学各专业录取分数线
  19. 大乐透兑奖规则|规则图
  20. java bmp 变色_java将图片(jpg/bmp/png)转16位bmp(RBG565)

热门文章

  1. 阻尼系数对控制系统的影响
  2. iterator 例子
  3. Mecanim的Avater
  4. SQLAPI数据库访问接口访问MySQL数据库
  5. 找感觉的第一个小程序
  6. Scrapy + 案例
  7. 摄影测量后方交会-前方交会(C#)
  8. 数据结构 实验报告07
  9. C++输出保留有效数字
  10. IPFS如何构建下一代互联网?