nuke-refresh-control
Version:
下拉刷新组件
165 lines (153 loc) • 4.51 kB
JSX
/** @jsx createElement */
import { Component, findDOMNode, createElement, setNativeProps, PropTypes } from 'rax';
import { isWeb } from 'nuke-env';
import View from 'nuke-view';
import addStyle from './add-style';
const defaultStyle = {
flexShrink: 0,
flexDirection: 'column-reverse',
display: 'flex',
overflow: 'hidden',
height: 0,
};
const FULL_WIDTH = 750;
const defaultHeight = 150;
class RefreshControl extends Component {
constructor(props) {
super(props);
this.getHeightPxValue();
this.addAnimStyle();
}
findDom() {
if (!this.dom) {
this.dom = findDOMNode(this.refs.webRefresh);
}
return this.dom;
}
setStyle(styleData) {
const elementStyle = this.findDom().style;
for (const styleName in styleData) {
elementStyle[styleName] = styleData[styleName];
}
}
getHeightPxValue() {
const { style = {} } = this.props;
const height = parseInt(style.height || defaultHeight, 10);
if (window.devicePixelRatio) {
if (typeof height === 'number') {
this.height = (height * window.screen.width) / FULL_WIDTH;
}
this.height = (height * window.screen.width) / FULL_WIDTH;
}
}
addAnim() {
setNativeProps(this.refs.webRefresh, { className: 'refreshAnim' });
}
removeAnim() {
setNativeProps(this.refs.webRefresh, { className: 'empty' });
}
// 展开下拉动画
setWebRefreshHeight = () => {
this.setStyle({
height: `${Math.floor(this.move / 3)}px`,
});
};
// 收起下拉动画
resetWebRefresh = () => {
if (this.move / 3 >= this.height) {
this.addAnim();
const list = findDOMNode(this.props.listId || 'list');
this.props.onRefresh && this.props.onRefresh();
} else {
this.removeAnim();
this.setStyle({
height: '0px',
});
}
};
/**
* 仿 iOS 下拉刷新逻辑
* 只有超过 refreshControl 的高度后才可以触发时间。
* 并执行快速回弹到固定高度的,继而按照动画回弹。
*/
addAnimStyle = () => {
// 下拉刷新 css 动画效果
const { animationTime: animTime } = this.props;
const animStr = `0% {height: ${this.height}px} 40% {height: ${this.height}px} 100% {height: 0px}`;
const strHTML = `.refreshAnim { animation:runWebRefresh ${animTime}s; -moz-animation:runWebRefresh ${animTime}s; -webkit-animation:runWebRefresh ${animTime}s; -o-animation:runWebRefresh ${animTime}s; } runWebRefresh {${animStr}} @-moz-keyframes runWebRefresh {${animStr}} @-webkit-keyframes runWebRefresh {${animStr}} @-o-keyframes runWebRefresh {${animStr}}`;
addStyle(strHTML);
};
setListEvent = () => {
const listId = this.props.listId;
// 绑定下拉刷新事件
setTimeout(() => {
const list = findDOMNode(listId || 'list');
if (!list) return;
list.addEventListener(
'touchstart',
(e) => {
this.startY = e.changedTouches[0].pageY;
},
false
);
list.addEventListener(
'touchmove',
(e) => {
this.moveY = e.changedTouches[0].pageY;
if (list.scrollTop == 0) {
this.move = this.moveY - this.startY;
this.setWebRefreshHeight();
if (this.move > 0) {
e.preventDefault();
}
}
},
false
);
list.addEventListener(
'touchend',
(e) => {
this.endY = e.changedTouches[0].pageY;
if (list.scrollTop == 0 && this.startY < this.endY) {
this.resetWebRefresh();
}
},
false
);
}, 300);
};
componentDidMount() {
this.setListEvent();
}
componentWillReceiveProps(nextProps) {
// if (nextProps.refreshing !== this.props.refreshing) {
if (!nextProps.refreshing) {
this.removeAnim();
this.setStyle({ height: '0px', overflow: 'hidden' });
}
// }
}
render() {
const { style } = this.props;
const refreshStyle = Object.assign({}, defaultStyle, style, { height: 0 });
if (isWeb) {
return (
<View ref="webRefresh" style={refreshStyle}>
{this.props.children}
</View>
);
}
return null;
}
}
RefreshControl.propTypes = {
animationTime: PropTypes.float,
isRefreshing: PropTypes.boolean,
onRefresh: PropTypes.func,
};
RefreshControl.defaultProps = {
animationTime: 1.5,
style: {},
};
RefreshControl.displayName = 'RefreshControl';
export default RefreshControl;