社区微信群开通啦,扫一扫抢先加入社区官方微信群
社区微信群
WindowScroller
跟随页面滚动(★★★)WindowScroller
高阶组件,让List组件跟随页面滚动(为List组件提供状态,同时还需要设置List组件的autoHeight属性)WindowScroller
高阶组件只能提供height,无法提供width<WindowScroller>
{({ height, isScrolling, scrollTop }) => (
<AutoSizer>
{({ width }) => (
<List
autoHeight // 设置高度为 WindowScroller 最终渲染的列表高度
// 组件的宽度
width={width} // 视口宽度
// 组件的高度
height={height} // 视口高度
rowCount={this.state.count} // List列表项总条目数
// 每行的高度
rowHeight={120} // 每一行高度
rowRenderer={this.renderHouseList}
isScrolling={isScrolling}
scrollTop={scrollTop}
/>
)}
</AutoSizer>
)}
</WindowScroller>
InfiniteLoader
组件(★★★)InfiniteLoader
组件,来实现无限滚动列表,从而加载更多房屋数据InfiniteLoader
文档示例,在项目中使用组件<InfiniteLoader
isRowLoaded={this.isRowLoaded}
loadMoreRows={this.loadMoreRows}
rowCount={count}
>
{({ onRowsRendered, registerChild }) => (
<WindowScroller>
{({ height, isScrolling, scrollTop }) => (
<AutoSizer>
{({ width }) => (
<List
onRowsRendered={onRowsRendered}
ref={registerChild}
autoHeight // 设置高度为 WindowScroller 最终渲染的列表高度
// 组件的宽度
width={width} // 视口宽度
// 组件的高度
height={height} // 视口高度
rowCount={count} // List列表项总条目数
// 每行的高度
rowHeight={120} // 每一行高度
rowRenderer={this.renderHouseList}
isScrolling={isScrolling}
scrollTop={scrollTop}
/>
)}
</AutoSizer>
)}
</WindowScroller>
)}
</InfiniteLoader>
// 判断每一行数据是否加载完毕
isRowLoaded = ({ index }) => {
return !!this.state.list[index];
};
// 用来获取更多房屋列表数据
// 注意,该方法的返回值是一个 Promise 对象,并且,这个对象应该在数据加载完成时,来调用 resolve让 Promise对象的状态变为已完成
loadMoreRows = ({ startIndex, stopIndex }) => {
return new Promise(resolve => {
...
});
};
loadMoreRows = ({ startIndex, stopIndex }) => {
return new Promise(resolve => {
instance
.get("/houses", {
params: {
cityId: value,
...this.filters,
start: startIndex,
end: stopIndex
}
})
.then(res => {
this.setState({
list: [...this.state.list, ...res.data.body.list]
});
// 加载数据完成时,调用resolve即可
resolve();
});
});
};
// 渲染每一行的内容
renderHouseList = ({
key, // Unique key within array of rows
index, // 索引号
style // 重点属性:一定要给每一个行数添加该样式
}) => {
// 当前这一行的
const { list } = this.state;
const house = list[index];
// 如果不存在,需要渲染loading元素占位
if (!house) {
return (
<div key={key} style={style}>
<p className={styles.loading}></p>
</div>
);
}
return (
...
);
};
<Sticky>
<Filter onFilter={this.onFilter} />
</Sticky>
class Sticky extends Component {
// 创建ref对象
placeholder = createRef()
content = createRef()
...
render() {
return (
<div>
{/* 占位元素 */}
<div ref={this.placeholder} />
{/* 内容元素 */}
<div ref={this.content}>{this.props.children}</div>
</div>
)
}
// 监听 scroll 事件
componentDidMount() {
window.addEventListener('scroll', this.handleScroll)
}
componentWillUnmount() {
window.removeEventListener('scroll', this.handleScroll)
}
// scroll 事件的事件处理程序
handleScroll = () => {
// 获取DOM对象
const placeholderEl = this.placeholder.current
const contentEl = this.content.current
const { top } = placeholderEl.getBoundingClientRect()
if (top < 0) {
// 吸顶
contentEl.classList.add(styles.fixed)
placeholderEl.style.height = '40px'
} else {
// 取消吸顶
contentEl.classList.remove(styles.fixed)
placeholderEl.style.height = '0px'
}
}
// HouseList组件
<Sticky height={40}>
<Filter onFilter={this.onFilter} />
</Sticky>
// Sticky 组件
handleScroll = () => {
const { height } = this.props;
...
const { top } = placeholderEl.getBoundingClientRect();
if (top < 0) {
// 吸顶
contentEl.classList.add(styles.fixed);
placeholderEl.style.height = `${height}px`;
} else {
// 取消吸顶
contentEl.classList.remove(styles.fixed);
placeholderEl.style.height = "0px";
}
};
renderMask() {
const { openType } = this.state
const isHide = openType === 'more' || openType === ''
return (
<Spring from={{ opacity: 0 }} to={{ opacity: isHide ? 0 : 1 }}>
{props => {
// 说明遮罩层已经完成动画效果,隐藏了
if (props.opacity === 0) {
return null
}
return (
<div
style={props}
className={styles.mask}
onClick={() => this.onCancel(openType)}
/>
)
}}
</Spring>
)
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!