forked from react-bootstrap/react-bootstrap
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathAffixMixin.js
123 lines (98 loc) · 3.19 KB
/
AffixMixin.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
/* global window, document */
import React from './react-es6';
import domUtils from './domUtils';
var AffixMixin = {
propTypes: {
offset: React.PropTypes.number,
offsetTop: React.PropTypes.number,
offsetBottom: React.PropTypes.number
},
getInitialState: function () {
return {
affixClass: 'affix-top'
};
},
getPinnedOffset: function (DOMNode) {
if (this.pinnedOffset) {
return this.pinnedOffset;
}
DOMNode.className = DOMNode.className.replace(/affix-top|affix-bottom|affix/, '');
DOMNode.className += DOMNode.className.length ? ' affix' : 'affix';
this.pinnedOffset = domUtils.getOffset(DOMNode).top - window.pageYOffset;
return this.pinnedOffset;
},
checkPosition: function () {
var DOMNode, scrollHeight, scrollTop, position, offsetTop, offsetBottom,
affix, affixType, affixPositionTop;
// TODO: or not visible
if (!this.isMounted()) {
return;
}
DOMNode = this.getDOMNode();
scrollHeight = document.documentElement.offsetHeight;
scrollTop = window.pageYOffset;
position = domUtils.getOffset(DOMNode);
offsetTop;
offsetBottom;
if (this.affixed === 'top') {
position.top += scrollTop;
}
offsetTop = this.props.offsetTop != null ?
this.props.offsetTop : this.props.offset;
offsetBottom = this.props.offsetBottom != null ?
this.props.offsetBottom : this.props.offset;
if (offsetTop == null && offsetBottom == null) {
return;
}
if (offsetTop == null) {
offsetTop = 0;
}
if (offsetBottom == null) {
offsetBottom = 0;
}
if (this.unpin != null && (scrollTop + this.unpin <= position.top)) {
affix = false;
} else if (offsetBottom != null && (position.top + DOMNode.offsetHeight >= scrollHeight - offsetBottom)) {
affix = 'bottom';
} else if (offsetTop != null && (scrollTop <= offsetTop)) {
affix = 'top';
} else {
affix = false;
}
if (this.affixed === affix) {
return;
}
if (this.unpin != null) {
DOMNode.style.top = '';
}
affixType = 'affix' + (affix ? '-' + affix : '');
this.affixed = affix;
this.unpin = affix === 'bottom' ?
this.getPinnedOffset(DOMNode) : null;
if (affix === 'bottom') {
DOMNode.className = DOMNode.className.replace(/affix-top|affix-bottom|affix/, 'affix-top');
affixPositionTop = scrollHeight - offsetBottom - DOMNode.offsetHeight - domUtils.getOffset(DOMNode).top;
}
this.setState({
affixClass: affixType,
affixPositionTop: affixPositionTop
});
},
checkPositionWithEventLoop: function () {
setTimeout(this.checkPosition, 0);
},
componentDidMount: function () {
window.addEventListener('scroll', this.checkPosition);
document.addEventListener('click', this.checkPositionWithEventLoop);
},
componentWillUnmount: function () {
window.removeEventListener('scroll', this.checkPosition);
document.addEventListener('click', this.checkPositionWithEventLoop);
},
componentDidUpdate: function (prevProps, prevState) {
if (prevState.affixClass === this.state.affixClass) {
this.checkPositionWithEventLoop();
}
}
};
export default = AffixMixin;