Merge pull request #1094 from ant-design/feat-affix-bottom

Feat affix bottom
This commit is contained in:
Benjy Cui 2016-03-09 15:40:22 +08:00
commit 3da8ea2412
5 changed files with 79 additions and 43 deletions

View File

@ -0,0 +1,17 @@
# 下方固定
- order: 2
固定在屏幕下方
---
````jsx
import { Affix, Button } from 'antd';
ReactDOM.render(
<Affix offsetBottom={20}>
<Button type="primary">固定在距离底部 20px 的位置</Button>
</Affix>
, mountNode);
````

View File

@ -10,7 +10,7 @@
import { Affix, Button } from 'antd';
ReactDOM.render(
<Affix offset={75}>
<Affix offsetTop={75}>
<Button type="primary">固定在距离顶部 75px 的位置</Button>
</Affix>
, mountNode);

View File

@ -1,13 +1,13 @@
import React from 'react';
import ReactDOM from 'react-dom';
import rcUtil from 'rc-util';
import { Dom } from 'rc-util';
import classNames from 'classnames';
function getScroll(w, top) {
let ret = w[`page${top ? 'Y' : 'X'}Offset`];
let method = `scroll${top ? 'Top' : 'Left'}`;
const method = `scroll${top ? 'Top' : 'Left'}`;
if (typeof ret !== 'number') {
let d = w.document;
const d = w.document;
// ie6,7,8 standard mode
ret = d.documentElement[method];
if (typeof ret !== 'number') {
@ -19,65 +19,82 @@ function getScroll(w, top) {
}
function getOffset(element) {
let rect = element.getBoundingClientRect();
let body = document.body;
let clientTop = element.clientTop || body.clientTop || 0;
let clientLeft = element.clientLeft || body.clientLeft || 0;
let scrollTop = getScroll(window, true);
let scrollLeft = getScroll(window);
const rect = element.getBoundingClientRect();
const body = document.body;
const clientTop = element.clientTop || body.clientTop || 0;
const clientLeft = element.clientLeft || body.clientLeft || 0;
const scrollTop = getScroll(window, true);
const scrollLeft = getScroll(window);
return {
top: rect.top + scrollTop - clientTop,
left: rect.left + scrollLeft - clientLeft
left: rect.left + scrollLeft - clientLeft,
};
}
let Affix = React.createClass({
getDefaultProps() {
return {
offset: 0
};
},
const Affix = React.createClass({
propTypes: {
offset: React.PropTypes.number
offsetTop: React.PropTypes.number,
offsetBottom: React.PropTypes.number,
},
getInitialState() {
return {
affix: false,
affixStyle: null
affixStyle: null,
};
},
handleScroll() {
let affix = this.state.affix;
let scrollTop = getScroll(window, true);
let elemOffset = getOffset(ReactDOM.findDOMNode(this));
let { offsetTop, offsetBottom } = this.props;
const scrollTop = getScroll(window, true);
const elemOffset = getOffset(ReactDOM.findDOMNode(this));
const elemSize = {
width: ReactDOM.findDOMNode(this.refs.fixedNode).offsetWidth,
height: ReactDOM.findDOMNode(this.refs.fixedNode).offsetHeight,
};
if (!affix && (elemOffset.top - this.props.offset) < scrollTop) {
this.setState({
affix: true,
affixStyle: {
top: this.props.offset,
left: elemOffset.left,
width: ReactDOM.findDOMNode(this).offsetWidth
}
});
const offsetMode = {};
if (typeof offsetTop !== 'number' && typeof offsetBottom !== 'number') {
offsetMode.top = true;
offsetTop = 0;
} else {
offsetMode.top = typeof offsetTop === 'number';
offsetMode.bottom = typeof offsetBottom === 'number';
}
if (affix && (elemOffset.top - this.props.offset) > scrollTop) {
if (scrollTop > elemOffset.top - offsetTop && offsetMode.top) {
// Fixed Top
if (!this.state.affixStyle) {
this.setState({
affixStyle: {
position: 'fixed',
top: offsetTop,
left: elemOffset.left,
},
});
}
} else if (scrollTop < elemOffset.top + elemSize.height + offsetBottom - window.innerHeight &&
offsetMode.bottom) {
// Fixed Bottom
if (!this.state.affixStyle) {
this.setState({
affixStyle: {
position: 'fixed',
bottom: offsetBottom,
left: elemOffset.left,
},
});
}
} else if (this.state.affixStyle) {
this.setState({
affix: false,
affixStyle: null
affixStyle: null,
});
}
},
componentDidMount() {
this.scrollEvent = rcUtil.Dom.addEventListener(window, 'scroll', this.handleScroll);
this.resizeEvent = rcUtil.Dom.addEventListener(window, 'resize', this.handleScroll);
this.scrollEvent = Dom.addEventListener(window, 'scroll', this.handleScroll);
this.resizeEvent = Dom.addEventListener(window, 'resize', this.handleScroll);
},
componentWillUnmount() {
@ -92,17 +109,17 @@ let Affix = React.createClass({
render() {
const className = classNames({
[this.props.className]: this.props.className,
'ant-affix': this.state.affix
'ant-affix': this.state.affixStyle,
});
return (
<div {...this.props}>
<div className={className} style={this.state.affixStyle}>
<div className={className} ref="fixedNode" style={this.state.affixStyle}>
{this.props.children}
</div>
</div>
);
}
},
});

View File

@ -18,4 +18,5 @@
| 成员 | 说明 | 类型 | 默认值 |
|-------------|----------------|--------------------|--------------|
| offset | 达到指定偏移量后触发 | Number | 0 |
| offsetTop | 距离窗口顶部达到指定偏移量后触发 | Number | |
| offsetBottom | 距离窗口底部达到指定偏移量后触发 | Number | |

View File

@ -1,3 +1,4 @@
.ant-affix {
position: fixed;
z-index: 10;
}