UNPKG

nuke-refresh-control

Version:

下拉刷新组件

165 lines (153 loc) 4.51 kB
/** @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; } @keyframes 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;