写的时候参考了非常多网络上的代码,故发出来共享,共同进步。
变量说明:
- NavBarHeight: 按需填入
- offset: 自行传入的修正偏移量(比如说,待固定的元素上方存在 margin-bottom)
- switched: 用以支持存在多个界面的 component ,但需要先给你的 component 添加 this.state.switched 并传入本模块来辅助判断
- classname & style: 略
import PropTypes from 'prop-types';
import React, { Component } from 'react';
class Affix extends Component {
static NavBarHeight = xxx;
constructor(props) {
super(props);
this.state = {
affix: false,
};
this.offset = 0;
}
componentDidMount() {
window.addEventListener('scroll', this.handleScroll);
this.offset = this.refs.fixedNode.getBoundingClientRect().top - Affix.NavBarHeight - this.props.offset;
}
componentWillReceiveProps(nextProps) {
if (this.props.switched !== nextProps.switched) {
this.setState({ affix: false });
}
}
componentDidUpdate(prevProps) {
if (this.props.switched !== prevProps.switched && !this.state.affix) {
this.offset = this.refs.fixedNode.getBoundingClientRect().top - Affix.NavBarHeight - this.props.offset;
}
}
componentWillUnmount() {
window.removeEventListener('scroll', this.handleScroll);
}
handleScroll = () => {
const affix = this.state.affix;
const scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
if (!affix && scrollTop >= this.offset) {
this.setState({
affix: true,
});
}
if (affix && scrollTop < this.offset) {
this.setState({
affix: false,
});
}
};
render() {
const affix = this.state.affix ? 'affix' : '';
const style = this.state.affix ? this.props.style : {};
const { className } = this.props;
return (
<div
className={`${className || ''} ${affix}`}
style={style}
ref={'fixedNode'}
>
{this.props.children}
</div>
);
}
}
Affix.propTypes = {
className: PropTypes.string,
offset: PropTypes.number,
style: PropTypes.object,
switched: PropTypes.bool,
};
Affix.defaultProps = {
className: '',
offset: 0,
style: {},
switched: false,
};
export default Affix;