布局结构
- wapper内外两层div包裹实际内容 第一层div=placeholder 占位有宽高的数据 无实际内容 另一层随窗口滚动计算位置fixed
- onResize重计算位置
- 开始渲染时 并未触发固钉效果,将正常渲染目标组件,后续计算可以拿到正常渲染时的宽高数据
- 留下来占位的一般需要不影响整体样式 比方说开始固钉效果后 原有展示没有很大缺陷
代码实现
// 第一层size监听 用于处理容器size变化
<ResizeObserver
onResize={() => {
this.updatePosition();
}}
>
<div {...props} ref={this.savePlaceholderNode}>
{affixStyle && <div style={placeholderStyle} aria-hidden="true" />}
<div className={className} ref={this.saveFixedNode} style={affixStyle}>
// 第二层size监听 用于处理内容size变化 有可能top或者bottom变化
<ResizeObserver
onResize={() => {
this.updatePosition();
}}
>
{children}
</ResizeObserver>
</div>
</div>
// 计算逻辑
// 固钉的样式数据 宽高等
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, // 当固钉开始fixed的时候 placeholder需要拿到正常渲染时的宽高占位
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,
};