Skip to content

Instantly share code, notes, and snippets.

@msociety
Last active January 27, 2017 17:53
Show Gist options
  • Save msociety/e3f886ec75f1f0295db2b73beb2d499f to your computer and use it in GitHub Desktop.
Save msociety/e3f886ec75f1f0295db2b73beb2d499f to your computer and use it in GitHub Desktop.
React Component FloatingAside
import React, { Component } from 'react';
const styles = {
wrapper: {
width: '100%',
padding: 0,
marginTop: '2.5em'
},
fixed: {
marginTop: 0,
position: 'fixed',
zIndex: '99',
top: '20px'
}
};
export default class FloatingAside extends Component {
constructor() {
super();
this._asideFixedTop = 20; // css value of "top" when comp is .fixed
this.state = {
asideTop: null,
asideHeight: null,
windowHeight: window.innerHeight,
parentWidth: null
};
this.bound_handleScroll = this.handleScroll.bind(this);
this.bound_handleResize = this.handleResize.bind(this);
}
// isScrolling: returns true it the top of this component is hidden
isScrolling() {
return ((this.state.asideTop !== null) &&
this.state.asideTop < this._asideFixedTop);
}
// isTooBig: returns true if this component is higher than window
isTooBig() {
return ((this.state.asideTop !== null) &&
((this.state.asideHeight + this._asideFixedTop) > this.state.windowHeight));
}
componentDidMount() {
let parentRect = this._asideRef.parentElement.getBoundingClientRect();
this.setState({
asideTop: parentRect.top + this._asideRef.offsetTop,
asideHeight: this._asideRef.scrollHeight, // paddings + content height
windowHeight: window.innerHeight,
parentWidth: this._asideRef.parentElement.clientWidth
});
window.addEventListener('scroll', this.bound_handleScroll);
window.addEventListener('resize', this.bound_handleResize);
}
componentWillUnmount() {
// http://stackoverflow.com/questions/11565471/removing-event-listener-which-was-added-with-bind
window.removeEventListener('scroll', this.bound_handleScroll);
window.removeEventListener('resize', this.bound_handleResize);
}
handleScroll() {
let parentRect = this._asideRef.parentElement.getBoundingClientRect();
this.setState({
asideTop: parentRect.top + this._asideRef.offsetTop,
asideHeight: this._asideRef.scrollHeight,
parentWidth: this._asideRef.parentElement.clientWidth
});
}
handleResize() {
let parentRect = this._asideRef.parentElement.getBoundingClientRect();
this.setState({
asideTop: parentRect.top + this._asideRef.offsetTop,
asideHeight: this._asideRef.scrollHeight, // paddings + content height
windowHeight: window.innerHeight,
parentWidth: this._asideRef.parentElement.clientWidth
});
}
render() {
let fixed = (this.isScrolling() && !this.isTooBig());
return (
<div style={styles.wrapper}>
<div class="clearfix"></div>
<aside
ref={(elem) => this._asideRef = elem}
style={fixed ? { ...styles.fixed, width: this.state.parentWidth } : {}}
>
{this.props.children}
</aside>
</div>
);
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment