nuke-scroll-view
Advanced tools
Comparing version 2.0.3 to 2.0.4
@@ -78,7 +78,10 @@ # ScrollView demo | ||
onEndReached={this.loadmore} | ||
showScrollBar={false} | ||
onScroll={e => { | ||
console.log(e); | ||
}} | ||
> | ||
<RefreshControl | ||
JDYHeaderStyle="endAnamtionStyle" | ||
refreshing={this.state.isRefreshing} | ||
style={[styles.itemRefresh]} | ||
style={styles.itemRefresh} | ||
onRefresh={this.handleRefresh} | ||
@@ -85,0 +88,0 @@ > |
@@ -22,74 +22,74 @@ # ScrollView demo | ||
let App = class NukeDemoIndex extends Component { | ||
constructor() { | ||
super(); | ||
//alert(height) | ||
} | ||
constructor() { | ||
super(); | ||
//alert(height) | ||
} | ||
render() { | ||
return ( | ||
<View style={styles.container}> | ||
<View style={styles.header}> This Is A Fixed Area </View> | ||
<ScrollView | ||
ref="vscroller" | ||
showsVerticalScrollIndicator={false} | ||
style={{ flex: 1 }} | ||
contentContainerStyle={{ | ||
backgroundColor: 'red', | ||
width: 750 | ||
}} | ||
> | ||
<Button size="small" type="primary" style={{ width: 200 }}> | ||
login | ||
</Button> | ||
<View style={styles.item}>Item1</View> | ||
<View style={styles.item}>Item2</View> | ||
<View style={styles.item}>Item2</View> | ||
<View style={styles.item}>Item2</View> | ||
<View style={styles.item}>Item2</View> | ||
<View style={styles.item}>Item2</View> | ||
</ScrollView> | ||
</View> | ||
); | ||
} | ||
render() { | ||
return ( | ||
<View style={styles.container}> | ||
<View style={styles.header}> This Is A Fixed Area </View> | ||
<ScrollView | ||
ref="vscroller" | ||
showsVerticalScrollIndicator={false} | ||
style={{ flex: 1 }} | ||
contentContainerStyle={{ | ||
backgroundColor: 'red', | ||
width: 750 | ||
}} | ||
> | ||
<Button size="small" type="primary" style={{ width: 200 }}> | ||
login | ||
</Button> | ||
<View style={styles.item}>Item1</View> | ||
<View style={styles.item}>Item2</View> | ||
<View style={styles.item}>Item2</View> | ||
<View style={styles.item}>Item2</View> | ||
<View style={styles.item}>Item2</View> | ||
<View style={styles.item}>Item2</View> | ||
</ScrollView> | ||
</View> | ||
); | ||
} | ||
}; | ||
const styles = { | ||
container: { | ||
flex: 1 | ||
}, | ||
header: { | ||
height: 200, | ||
width: 750, | ||
color: '#425B81', | ||
backgroundColor: '#ADEADE', | ||
alignItems: 'center', | ||
justifyContent: 'center' | ||
}, | ||
inputwrap: { | ||
height: 80 | ||
}, | ||
input: { | ||
height: 80 | ||
}, | ||
item: { | ||
height: '300rem', | ||
minHeight: '300rem', | ||
alignItems: 'center', | ||
justifyContent: 'center' | ||
}, | ||
bottom: { | ||
height: 80 | ||
}, | ||
bottomView: { | ||
flex: 1, | ||
backgroundColor: '#ACEACE' | ||
}, | ||
item: { | ||
height: 200, | ||
width: 650, | ||
alignItems: 'center', | ||
justifyContent: 'center', | ||
backgroundColor: '#F25195' | ||
} | ||
container: { | ||
flex: 1 | ||
}, | ||
header: { | ||
height: 200, | ||
width: 750, | ||
color: '#425B81', | ||
backgroundColor: '#ADEADE', | ||
alignItems: 'center', | ||
justifyContent: 'center' | ||
}, | ||
inputwrap: { | ||
height: 80 | ||
}, | ||
input: { | ||
height: 80 | ||
}, | ||
item: { | ||
height: '300rem', | ||
minHeight: '300rem', | ||
alignItems: 'center', | ||
justifyContent: 'center' | ||
}, | ||
bottom: { | ||
height: 80 | ||
}, | ||
bottomView: { | ||
flex: 1, | ||
backgroundColor: '#ACEACE' | ||
}, | ||
item: { | ||
height: 200, | ||
width: 650, | ||
alignItems: 'center', | ||
justifyContent: 'center', | ||
backgroundColor: '#F25195' | ||
} | ||
}; | ||
render(<App />); | ||
``` |
# ScrollView demo 事件 | ||
- order: 0 | ||
* order: 0 | ||
@@ -9,6 +9,5 @@ 可以滚动到指定位置 | ||
````js | ||
```js | ||
/** @jsx createElement */ | ||
import {createElement, Component,render} from 'rax'; | ||
import { createElement, Component, render } from 'rax'; | ||
import View from 'nuke-view'; | ||
@@ -22,72 +21,114 @@ import Text from 'nuke-text'; | ||
let App = class NukeDemoIndex extends Component { | ||
constructor() { | ||
super(); | ||
constructor() { | ||
super(); | ||
} | ||
getRandomColor() { | ||
var rgb = | ||
'rgb(' + | ||
Math.floor(Math.random() * 255) + | ||
',' + | ||
Math.floor(Math.random() * 255) + | ||
',' + | ||
Math.floor(Math.random() * 255) + | ||
')'; | ||
return rgb; | ||
} | ||
getViews() { | ||
let doms = []; | ||
for (var i = 0; i <= 10; i++) { | ||
doms.push( | ||
<View style={[styles.item, { backgroundColor: this.getRandomColor() }]}> | ||
<Text>第{i}个</Text> | ||
</View> | ||
); | ||
} | ||
getRandomColor(){ | ||
var rgb='rgb('+Math.floor(Math.random()*255)+',' | ||
+Math.floor(Math.random()*255)+',' | ||
+Math.floor(Math.random()*255)+')'; | ||
return rgb; | ||
} | ||
getViews(){ | ||
let doms=[]; | ||
for(var i=0; i<= 10;i++){ | ||
doms.push(<View style={[styles.item,{backgroundColor:this.getRandomColor()}]}><Text>第{i}个</Text></View>) | ||
} | ||
return doms; | ||
} | ||
scroll=()=>{ | ||
this.refs.scroller1.scrollTo({x:0,y:100}) | ||
} | ||
scrollHandler=(e)=>{ | ||
console.log(e); | ||
} | ||
reset = ()=>{ | ||
return doms; | ||
} | ||
scroll = () => { | ||
this.refs.scroller1.scrollTo({ x: 0, y: 100 }); | ||
}; | ||
scrollHandler = e => { | ||
console.log(e); | ||
}; | ||
scrollToElement = e => { | ||
this.refs.scroller1.scrollToElement(this.refs.specialView); | ||
}; | ||
reset = () => { | ||
this.refs.scroller1.resetLoadmore(); | ||
Modal.toast('reset loadmore success'); | ||
}; | ||
loadmore = () => { | ||
Modal.toast('无新增数据'); | ||
}; | ||
render() { | ||
return ( | ||
<Page title="ScrollView"> | ||
<Page.Intro main="events" /> | ||
<ScrollView | ||
onScroll={this.scrollHandler} | ||
ref="scroller1" | ||
style={styles.scroller} | ||
onEndReachedThreshold={20} | ||
onEndReached={this.loadmore} | ||
> | ||
{this.getViews()} | ||
<View | ||
style={{ height: 400, backgroundColor: '#9fb64b' }} | ||
ref="specialView" | ||
> | ||
<Text>special</Text> | ||
</View> | ||
<View style={{ height: 400 }}> | ||
<Text>others</Text> | ||
</View> | ||
</ScrollView> | ||
<View style={{ marginTop: '30rem' }}> | ||
<Button type="primary" style={styles.btn} block onPress={this.scroll}> | ||
滑动到指定位移: 100rem | ||
</Button> | ||
this.refs.scroller1.resetLoadmore(); | ||
Modal.toast('reset loadmore success'); | ||
} | ||
loadmore=()=>{ | ||
Modal.toast('无新增数据'); | ||
} | ||
render() { | ||
return ( | ||
<Page title="ScrollView"> | ||
<Page.Intro main="events"></Page.Intro> | ||
<ScrollView onScroll={this.scrollHandler} ref="scroller1" style={styles.scroller} disabledPtr={true} onEndReachedThreshold={20} onEndReached={this.loadmore}> | ||
{this.getViews()} | ||
</ScrollView> | ||
<Button.Group style={{marginTop:'30rem'}}> | ||
<Button type="primary" onPress={this.scroll}>滑动到100rem 位置</Button> | ||
<Button type="primary" onPress={this.reset}>reset load more</Button> | ||
</Button.Group> | ||
</Page> | ||
) | ||
} | ||
} | ||
const styles={ | ||
scroller:{ | ||
backgroundColor:'#ffffff', | ||
height:'400rem' | ||
}, | ||
st:{ | ||
paddingTop:'10rem', | ||
paddingBottom:'10rem', | ||
paddingLeft:'20rem', | ||
backgroundColor:'#dddddd' | ||
}, | ||
stText:{ | ||
fontSize:'36rem' | ||
}, | ||
item:{ | ||
height:'120rem', | ||
alignItems:'center', | ||
justifyContent:'center', | ||
borderBottomStyle:'solid', | ||
borderBottomWidth:'1rem', | ||
borderBottomColor:'#e8e8e8' | ||
} | ||
} | ||
render(<App/>); | ||
<Button | ||
type="primary" | ||
style={styles.btn} | ||
block | ||
onPress={this.scrollToElement} | ||
> | ||
滑动到指定元素:ref = specialView | ||
</Button> | ||
```` | ||
<Button type="primary" style={styles.btn} block onPress={this.reset}> | ||
底部拉取不到新增数据时 resetLoadMore 触发再次拉取 | ||
</Button> | ||
</View> | ||
</Page> | ||
); | ||
} | ||
}; | ||
const styles = { | ||
scroller: { | ||
backgroundColor: '#ffffff', | ||
height: '400rem' | ||
}, | ||
st: { | ||
paddingTop: '10rem', | ||
paddingBottom: '10rem', | ||
paddingLeft: '20rem', | ||
backgroundColor: '#dddddd' | ||
}, | ||
stText: { | ||
fontSize: '36rem' | ||
}, | ||
item: { | ||
height: '120rem', | ||
alignItems: 'center', | ||
justifyContent: 'center', | ||
borderBottomStyle: 'solid', | ||
borderBottomWidth: '1rem', | ||
borderBottomColor: '#e8e8e8' | ||
}, | ||
btn: { | ||
marginBottom: 20 | ||
} | ||
}; | ||
render(<App />); | ||
``` |
# Changelog | ||
## 2.0.4 / 2018-05-09 | ||
* [[81b8b0e](http://gitlab.alibaba-inc.com/nuke/scroll-view/commit/81b8b0e1369ff34c7da8a1e9e57e70d12ea73e1f)] - `refactor` done | ||
## 2.0.3 / 2018-04-09 | ||
@@ -5,0 +9,0 @@ |
450
lib/index.js
'use strict'; | ||
/** @jsx createElement */ | ||
@@ -22,6 +23,2 @@ | ||
var _nukeText = require('nuke-text'); | ||
var _nukeText2 = _interopRequireDefault(_nukeText); | ||
var _nukeRefreshControl = require('nuke-refresh-control'); | ||
@@ -31,8 +28,10 @@ | ||
var _webRefreshControl = require('./web-refresh-control'); | ||
var _styles = require('./styles'); | ||
var _webRefreshControl2 = _interopRequireDefault(_webRefreshControl); | ||
var _styles2 = _interopRequireDefault(_styles); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; } | ||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } | ||
@@ -44,2 +43,3 @@ | ||
var SCROLLVIEW_CLS = 'rax-scrollview'; | ||
var isWeex = _nukeEnv2.default.isWeex, | ||
@@ -49,15 +49,10 @@ isWeb = _nukeEnv2.default.isWeb; | ||
var DEFAULT_END_REACHED_THRESHOLD = 500; | ||
var DEFAULT_SCROLL_CALLBACK_THROTTLE = 50; | ||
var LOADMORE_THRESHOLD = 500; | ||
var ON_SCROLL_THROTTLE = 50; | ||
var FULL_WIDTH = 750; | ||
function formatRemToPx(value) { | ||
if (window.devicePixelRatio) { | ||
if (typeof value === 'number') { | ||
return value * window.screen.width / FULL_WIDTH; | ||
} else { | ||
return value.replace('rem', '') * window.screen.width / FULL_WIDTH; | ||
} | ||
} | ||
} | ||
/** | ||
* ScrollView | ||
* @description 可滚动容器 | ||
*/ | ||
@@ -72,42 +67,58 @@ var ScrollView = function (_Component) { | ||
_this.state = { | ||
loadmoreretry: 0 | ||
}; | ||
_this.lastScrollContentSize = 0; | ||
_this.lastScrollDistance = 0; | ||
_this.lastScrollContentSize = 0; | ||
_this.loadmoreretry = 1; | ||
_this.handleScroll = function (e) { | ||
_this.handleScroll = _this.handleScroll.bind(_this); | ||
_this.scrollTo = _this.scrollTo.bind(_this); | ||
_this.scrollToElement = _this.scrollToElement.bind(_this); | ||
_this.resetLoadmore = _this.resetLoadmore.bind(_this); | ||
return _this; | ||
} | ||
_createClass(ScrollView, [{ | ||
key: 'handleScroll', | ||
value: function handleScroll(e) { | ||
var _props = this.props, | ||
onScroll = _props.onScroll, | ||
horizontal = _props.horizontal, | ||
onEndReached = _props.onEndReached, | ||
onEndReachedThreshold = _props.onEndReachedThreshold; | ||
if (isWeb) { | ||
if (_this.props.onScroll) { | ||
if (onScroll) { | ||
e.nativeEvent = { | ||
get contentOffset() { | ||
return { | ||
x: e.target.scrollLeft, | ||
y: e.target.scrollTop | ||
}; | ||
contentOffset: { | ||
x: e.target.scrollLeft, | ||
y: e.target.scrollTop | ||
} | ||
}; | ||
_this.props.onScroll(e); | ||
onScroll && onScroll(e); | ||
} | ||
if (_this.props.onEndReached) { | ||
if (!_this.scrollerNode) { | ||
_this.scrollerNode = (0, _rax.findDOMNode)(_this.refs.scroller); | ||
_this.scrollerContentNode = (0, _rax.findDOMNode)(_this.refs.contentContainer); | ||
if (onEndReached) { | ||
if (!this.scrollerNode) { | ||
this.scrollerNode = (0, _rax.findDOMNode)(this.refs.scroller); | ||
this.scrollerContentNode = (0, _rax.findDOMNode)(this.refs.contentContainer); | ||
_this.scrollerNodeSize = _this.props.horizontal ? _this.scrollerNode.offsetWidth : _this.scrollerNode.offsetHeight; | ||
this.scrollerNodeSize = horizontal ? this.scrollerNode.offsetWidth : this.scrollerNode.offsetHeight; | ||
} | ||
// NOTE:in iOS7/8 offsetHeight/Width is is inaccurate ( use scrollHeight/Width ) | ||
var scrollContentSize = _this.props.horizontal ? _this.scrollerNode.scrollWidth : _this.scrollerNode.scrollHeight; | ||
var scrollDistance = _this.props.horizontal ? _this.scrollerNode.scrollLeft : _this.scrollerNode.scrollTop; | ||
var isEndReached = scrollContentSize - scrollDistance - _this.scrollerNodeSize < _this.props.onEndReachedThreshold; | ||
var scrollContentSize = horizontal ? this.scrollerNode.scrollWidth : this.scrollerNode.scrollHeight; | ||
var scrollDistance = horizontal ? this.scrollerNode.scrollLeft : this.scrollerNode.scrollTop; | ||
var isEndReached = scrollContentSize - scrollDistance - this.scrollerNodeSize < onEndReachedThreshold; | ||
var isScrollToEnd = scrollDistance > _this.lastScrollDistance; | ||
var isLoadedMoreContent = scrollContentSize != _this.lastScrollContentSize; | ||
var isScrollToEnd = scrollDistance > this.lastScrollDistance; | ||
var isLoadedMoreContent = scrollContentSize !== this.lastScrollContentSize; | ||
if (isEndReached && isScrollToEnd && isLoadedMoreContent) { | ||
_this.lastScrollContentSize = scrollContentSize; | ||
_this.props.onEndReached(e); | ||
this.lastScrollContentSize = scrollContentSize; | ||
onEndReached(e); | ||
} | ||
_this.lastScrollDistance = scrollDistance; | ||
this.lastScrollDistance = scrollDistance; | ||
} | ||
@@ -123,24 +134,40 @@ } | ||
}; | ||
_this.props.onScroll(e); | ||
onScroll && onScroll(e); | ||
} | ||
}; | ||
} | ||
/** | ||
* 兼容旧的 resetScroll | ||
*/ | ||
_this.resetLoadmore = function () { | ||
}, { | ||
key: 'resetLoadmore', | ||
value: function resetLoadmore() { | ||
if (isWeb) { | ||
_this.lastScrollContentSize = 0; | ||
_this.lastScrollDistance = 0; | ||
this.lastScrollContentSize = 0; | ||
this.lastScrollDistance = 0; | ||
} else { | ||
_this.refs.scroller.resetLoadmore(); | ||
this.refs.scroller.resetLoadmore(); | ||
} | ||
}; | ||
} | ||
}, { | ||
key: 'scrollTo', | ||
value: function scrollTo() { | ||
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; | ||
var horizontal = this.props.horizontal; | ||
var _options$x = options.x, | ||
x = _options$x === undefined ? 0 : _options$x, | ||
_options$y = options.y, | ||
y = _options$y === undefined ? 0 : _options$y, | ||
_options$animated = options.animated, | ||
animated = _options$animated === undefined ? true : _options$animated, | ||
_options$offset = options.offset, | ||
offset = _options$offset === undefined ? 0 : _options$offset; | ||
_this.scrollTo = function (options) { | ||
var x = parseInt(options.x); | ||
var y = parseInt(options.y); | ||
var offsetResult = parseInt(horizontal ? x : y || offset, 10); | ||
if (isWeex) { | ||
var dom = require('@weex-module/dom'); | ||
var contentContainer = (0, _rax.findDOMNode)(_this.refs.contentContainer); | ||
var contentContainer = (0, _rax.findDOMNode)(this.refs.contentContainer); | ||
dom.scrollToElement(contentContainer.ref, { | ||
offset: x || y || 0 | ||
offset: offsetResult, | ||
animated: animated | ||
}); | ||
@@ -150,36 +177,39 @@ } else { | ||
if (x >= 0) { | ||
(0, _rax.findDOMNode)(_this.refs.scroller).scrollLeft = pixelRatio * x; | ||
if (horizontal) { | ||
(0, _rax.findDOMNode)(this.refs.scroller).scrollLeft = pixelRatio * offsetResult; | ||
} else { | ||
(0, _rax.findDOMNode)(this.refs.scroller).scrollTop = pixelRatio * offsetResult; | ||
} | ||
} | ||
} | ||
}, { | ||
key: 'scrollToElement', | ||
value: function scrollToElement(ref) { | ||
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; | ||
var _options$offset2 = options.offset, | ||
offset = _options$offset2 === undefined ? 0 : _options$offset2, | ||
_options$animated2 = options.animated, | ||
animated = _options$animated2 === undefined ? true : _options$animated2; | ||
if (y >= 0) { | ||
(0, _rax.findDOMNode)(_this.refs.scroller).scrollTop = pixelRatio * y; | ||
if (isWeex) { | ||
var dom = require('@weex-module/dom'); | ||
// const contentContainer = findDOMNode(this.refs.contentContainer); | ||
dom.scrollToElement((0, _rax.findDOMNode)(ref), { | ||
offset: offset, | ||
animated: animated | ||
}); | ||
} else { | ||
var pixelRatio = document.documentElement.clientWidth / FULL_WIDTH; | ||
if (offset >= 0) { | ||
var refDOM = (0, _rax.findDOMNode)(ref); | ||
if (refDOM) { | ||
(0, _rax.findDOMNode)(this.refs.scroller).scrollTop = refDOM.offsetTop + pixelRatio * offset; | ||
} | ||
} | ||
} | ||
}; | ||
_this.handleRefresh = function () { | ||
return new Promise(function (resolve, reject) { | ||
_this.onRefresh && _this.onRefresh(resolve, reject); | ||
}); | ||
}; | ||
_this.state = { | ||
loadmoreretry: 0 | ||
}; | ||
_this.onRefresh = null; | ||
// unit is px; | ||
_this.refreshHeight = 150; | ||
return _this; | ||
} | ||
/** | ||
* 兼容旧的resetScroll | ||
*/ | ||
_createClass(ScrollView, [{ | ||
} | ||
}, { | ||
key: 'splitChildren', | ||
value: function splitChildren() { | ||
var _this2 = this; | ||
var children = this.props.children; | ||
@@ -191,12 +221,10 @@ | ||
if (Array.isArray(children)) { | ||
children.map(function (child, index) { | ||
if (child && child.type && child.type.displayName === _nukeRefreshControl2.default.displayName) { | ||
for (var index = 0; index < children.length; index++) { | ||
var child = children[index]; | ||
if (child.type && child.type.displayName === _nukeRefreshControl2.default.displayName) { | ||
refreshContent = child; | ||
// format to px | ||
_this2.refreshHeight = child.props.style && child.props.style.height && formatRemToPx(child.props.style.height) || 80; | ||
_this2.onRefresh = child.props.onRefresh; | ||
} else { | ||
contents.push(child); | ||
} | ||
}); | ||
} | ||
} | ||
@@ -210,39 +238,37 @@ this.childrenAll = { | ||
}, { | ||
key: 'hideWebScrollBar', | ||
value: function hideWebScrollBar() { | ||
var styleNode = document.createElement('style'); | ||
styleNode.id = 'rax-scrollview-style'; | ||
document.head.appendChild(styleNode); | ||
styleNode.innerHTML = '.' + SCROLLVIEW_CLS + '::-webkit-scrollbar{display: none;}'; | ||
} | ||
}, { | ||
key: 'render', | ||
value: function render() { | ||
var _this3 = this; | ||
var _props2 = this.props, | ||
style = _props2.style, | ||
scrollEventThrottle = _props2.scrollEventThrottle, | ||
showsHorizontalScrollIndicator = _props2.showsHorizontalScrollIndicator, | ||
showsVerticalScrollIndicator = _props2.showsVerticalScrollIndicator, | ||
onEndReached = _props2.onEndReached, | ||
onScroll = _props2.onScroll, | ||
children = _props2.children, | ||
horizontal = _props2.horizontal, | ||
onEndReachedThreshold = _props2.onEndReachedThreshold, | ||
others = _objectWithoutProperties(_props2, ['style', 'scrollEventThrottle', 'showsHorizontalScrollIndicator', 'showsVerticalScrollIndicator', 'onEndReached', 'onScroll', 'children', 'horizontal', 'onEndReachedThreshold']); | ||
var _props = this.props, | ||
id = _props.id, | ||
style = _props.style, | ||
scrollEventThrottle = _props.scrollEventThrottle, | ||
showsHorizontalScrollIndicator = _props.showsHorizontalScrollIndicator, | ||
showsVerticalScrollIndicator = _props.showsVerticalScrollIndicator, | ||
onEndReached = _props.onEndReached, | ||
onEndReachedThreshold = _props.onEndReachedThreshold, | ||
onScroll = _props.onScroll, | ||
children = _props.children, | ||
horizontal = _props.horizontal; | ||
var showScrollBar = this.props.showScrollBar; | ||
// In weex must be int value | ||
if (typeof showScrollBar === 'undefined') { | ||
showScrollBar = horizontal ? showsHorizontalScrollIndicator : showsVerticalScrollIndicator; | ||
} | ||
onEndReachedThreshold = parseInt(onEndReachedThreshold, 10); | ||
var contentContainerStyle = [horizontal && _styles2.default.contentContainerHorizontal, this.props.contentContainerStyle]; | ||
var contentContainerStyle = [horizontal && styles.contentContainerHorizontal, this.props.contentContainerStyle]; | ||
// bugfix: fix scrollview flex in ios 78 | ||
if (!isWeex && !horizontal) { | ||
contentContainerStyle.push(styles.containerWebStyle); | ||
contentContainerStyle.push(_styles2.default.containerWebStyle); | ||
} | ||
if (this.props.style) { | ||
var childLayoutProps = ['alignItems', 'justifyContent'].filter(function (prop) { | ||
return _this3.props.style[prop] !== undefined; | ||
}); | ||
if (childLayoutProps.length !== 0) { | ||
console.warn('ScrollView child layout (' + JSON.stringify(childLayoutProps) + ') must be applied through the contentContainerStyle prop.'); | ||
} | ||
} | ||
this.splitChildren(); | ||
@@ -254,88 +280,52 @@ var contentChild = this.childrenAll.contents; | ||
_nukeView2.default, | ||
{ | ||
x: 'contentContainer', | ||
ref: 'contentContainer', | ||
style: contentContainerStyle | ||
}, | ||
{ ref: 'contentContainer', style: contentContainerStyle }, | ||
contentChild | ||
); | ||
var baseStyle = horizontal ? styles.horizontal : styles.vertical; | ||
var baseStyle = horizontal ? _styles2.default.horizontal : _styles2.default.vertical; | ||
var scrollerStyle = Object.assign({}, horizontal ? styles.horizontal : styles.vertical, this.props.style); | ||
var scrollerStyle = Object.assign({}, baseStyle, isWeb ? _styles2.default.scrollerWeb : {}, this.props.style); | ||
var showsScrollIndicator = horizontal ? showsHorizontalScrollIndicator : showsVerticalScrollIndicator; | ||
if (isWeex) { | ||
var nativeProps = { | ||
style: scrollerStyle, | ||
showScrollbar: showScrollBar, | ||
onLoadmore: onEndReached, | ||
onScroll: onScroll ? this.handleScroll : null, | ||
loadmoreoffset: parseInt(onEndReachedThreshold, 10), | ||
loadmoreretry: true, | ||
scrollDirection: horizontal ? 'horizontal' : 'vertical' | ||
}; | ||
return (0, _rax.createElement)( | ||
'scroller', | ||
_extends({}, this.props, { | ||
ref: 'scroller', | ||
style: scrollerStyle, | ||
showScrollbar: showsScrollIndicator, | ||
onLoadmore: onEndReached, | ||
onScroll: onScroll ? this.handleScroll : null, | ||
loadmoreoffset: onEndReachedThreshold, | ||
loadmoreretry: this.state.loadmoreretry, | ||
scrollDirection: this.props.horizontal ? 'horizontal' : 'vertical' | ||
}), | ||
_extends({}, this.others, { ref: 'scroller' }, nativeProps), | ||
refreshContent, | ||
contentContainer | ||
); | ||
} else { | ||
var handleScroll = this.handleScroll; | ||
if (scrollEventThrottle) { | ||
handleScroll = throttle(handleScroll, scrollEventThrottle); | ||
} | ||
if (!showsScrollIndicator && !document.getElementById('rax-scrollview-style')) { | ||
var styleNode = document.createElement('style'); | ||
styleNode.id = 'rax-scrollview-style'; | ||
document.head.appendChild(styleNode); | ||
styleNode.innerHTML = '.' + this.props.className + '::-webkit-scrollbar{display: none;}'; | ||
} | ||
scrollerStyle.webkitOverflowScrolling = 'touch'; | ||
scrollerStyle.overflow = 'scroll'; | ||
var webProps = _extends({}, this.props, { | ||
ref: 'scroller', | ||
style: scrollerStyle, | ||
onScroll: handleScroll | ||
}); | ||
delete webProps.onEndReachedThreshold; | ||
if (this.props.disabledPtr) { | ||
return (0, _rax.createElement)( | ||
_nukeView2.default, | ||
webProps, | ||
contentContainer | ||
); | ||
} | ||
if (refreshContent) { | ||
var childEle = (0, _rax.cloneElement)(refreshContent); | ||
var childProps = childEle.props; | ||
return (0, _rax.createElement)( | ||
_nukeView2.default, | ||
_extends({}, webProps, { id: 'scroller_rv' }), | ||
(0, _rax.createElement)( | ||
_webRefreshControl2.default, | ||
{ | ||
listId: 'scroller_rv', | ||
refreshingTime: 100, | ||
height: this.refreshHeight, | ||
refreshing: childProps.refreshing, | ||
onRefresh: this.onRefresh | ||
}, | ||
childEle | ||
), | ||
contentContainer | ||
); | ||
} else { | ||
return (0, _rax.createElement)( | ||
_nukeView2.default, | ||
_extends({}, webProps, { id: 'scroller_rv' }), | ||
contentContainer | ||
); | ||
} | ||
} | ||
/** | ||
* trigger times throttle | ||
*/ | ||
var handleScroll = this.handleScroll; | ||
if (scrollEventThrottle) { | ||
handleScroll = throttle(handleScroll, scrollEventThrottle); | ||
} | ||
var webProps = _extends({ | ||
ref: 'scroller', | ||
style: scrollerStyle, | ||
onScroll: handleScroll | ||
}, others); | ||
if (!showScrollBar) { | ||
this.hideWebScrollBar(); | ||
} | ||
return (0, _rax.createElement)( | ||
_nukeView2.default, | ||
_extends({}, webProps, { id: 'scroller_rv', className: SCROLLVIEW_CLS }), | ||
refreshContent ? (0, _rax.createElement)(_nukeRefreshControl2.default, _extends({}, refreshContent.props, { | ||
listId: 'scroller_rv', | ||
refreshingTime: 100, | ||
refreshing: refreshContent.props.refreshing | ||
})) : null, | ||
contentContainer | ||
); | ||
} | ||
@@ -347,13 +337,7 @@ }]); | ||
ScrollView.defaultProps = { | ||
scrollEventThrottle: DEFAULT_SCROLL_CALLBACK_THROTTLE, | ||
onEndReachedThreshold: DEFAULT_END_REACHED_THRESHOLD, | ||
showsHorizontalScrollIndicator: true, | ||
showsVerticalScrollIndicator: true, | ||
className: 'rax-scrollview' | ||
}; | ||
function throttle(func, wait) { | ||
var ctx, args, rtn, timeoutID; | ||
var ctx = void 0; | ||
var args = void 0; | ||
var rtn = void 0; | ||
var timeoutID = void 0; | ||
var last = 0; | ||
@@ -373,3 +357,5 @@ | ||
var delta = new Date() - last; | ||
if (!timeoutID) if (delta >= wait) call();else timeoutID = setTimeout(call, wait - delta); | ||
if (!timeoutID) { | ||
if (delta >= wait) call();else timeoutID = setTimeout(call, wait - delta); | ||
} | ||
return rtn; | ||
@@ -379,25 +365,53 @@ }; | ||
var styles = { | ||
vertical: { | ||
flex: 1, | ||
flexDirection: 'column' | ||
}, | ||
horizontal: { | ||
flex: 1, | ||
flexDirection: 'row' | ||
}, | ||
contentContainerHorizontal: { | ||
flexDirection: 'row' | ||
}, | ||
containerWebStyle: { | ||
display: 'block' | ||
} | ||
ScrollView.propTypes = { | ||
/** | ||
* ScrollView 样式 style of ScrollView | ||
*/ | ||
style: _rax.PropTypes.any, | ||
/** | ||
* 滚动时回调 callback when scrolling | ||
*/ | ||
onScroll: _rax.PropTypes.func, | ||
/** | ||
* 加载到底部时回调 callback when scrolling to bottom | ||
*/ | ||
onEndReached: _rax.PropTypes.func, | ||
/** | ||
* 是否横向 is horizontal | ||
*/ | ||
horizontal: _rax.PropTypes.boolean, | ||
/** | ||
* 触发加载到底部回调的位移 offset of scrolling to bottom event been triggered | ||
*/ | ||
onEndReachedThreshold: _rax.PropTypes.number, | ||
/** | ||
* 是否展示横向滚动条 is show horizontal scrollbar | ||
*/ | ||
showsHorizontalScrollIndicator: _rax.PropTypes.boolean, | ||
/** | ||
* 是否展示纵向滚动条 is show vertical scrollbar | ||
*/ | ||
showsVerticalScrollIndicator: _rax.PropTypes.boolean, | ||
/** | ||
* 内容容器样式 the style of content's wrap container | ||
*/ | ||
contentContainerStyle: _rax.PropTypes.any, | ||
/** | ||
* onScroll 事件触发节流时间 the time inteval of next onScroll event being triggered | ||
*/ | ||
scrollEventThrottle: _rax.PropTypes.number, | ||
children: _rax.PropTypes.any | ||
}; | ||
ScrollView.PropTypes = { | ||
style: _rax.PropTypes.Object | ||
}; | ||
ScrollView.defaultProps = { | ||
style: {} | ||
style: {}, | ||
contentContainerStyle: {}, | ||
horizontal: false, | ||
onScroll: null, | ||
onEndReached: function onEndReached() {}, | ||
scrollEventThrottle: ON_SCROLL_THROTTLE, | ||
onEndReachedThreshold: LOADMORE_THRESHOLD, | ||
showsHorizontalScrollIndicator: true, | ||
showsVerticalScrollIndicator: true | ||
}; | ||
exports.default = ScrollView; | ||
module.exports = exports['default']; |
{ | ||
"name": "nuke-scroll-view", | ||
"version": "2.0.3", | ||
"version": "2.0.4", | ||
"description": "滚动组件", | ||
@@ -60,3 +60,9 @@ "main": "lib/index", | ||
"nuke-modal": "^1.x.x", | ||
"nuke-text": "^0.x.x" | ||
"nuke-text": "^0.x.x", | ||
"eslint": "3.19.0", | ||
"babel-eslint": "^7.2.3", | ||
"eslint-config-ali": "2.0.0", | ||
"eslint-plugin-import": "2.6.0", | ||
"eslint-plugin-jsx-a11y": "6.0.2", | ||
"eslint-plugin-react": "7.1.0" | ||
}, | ||
@@ -63,0 +69,0 @@ "publishConfig": { |
@@ -13,27 +13,82 @@ # ScrollView | ||
| 属性 | 说明 | 类型 | 默认值 | | ||
| ------------------------------ | --------------------------------------------------------------------- | -------- | ------ | | ||
| horizontal | 是否横向 | boolean | false | | ||
| showsHorizontalScrollIndicator | 是否显示水平滚动条 | boolean | true | | ||
| showsVerticalScrollIndicator | 是否显示垂直滚动条 | boolean | true | | ||
| onEndReachedThreshold | 设置加载更多的偏移 | string | 500rem | | ||
| onEndReached | 滚动到底部时的事件( 距离底部 onEndReachedThreshold 长度时触发) | event | 无 | | ||
| scrollEventThrottle | 在滚动过程中,scroll 事件被调用的频率(默认值为 100),用于滚动的节流 | number | 100 | | ||
| onScroll | 滚动时触发的事件 | function | | ||
| style | 容器样式 | object | 无 | | ||
| contentContainerStyle | 容器内部 container 样式 | 无 | | ||
| 属性 | 说明 | 类型 | 默认值 | | ||
| -------------------------------------- | --------------------------------------------------------------------- | -------- | ------ | | ||
| horizontal | 是否横向 | boolean | false | | ||
| showScrollBar | 是否显示滚动条 | boolean | true | | ||
| showsHorizontalScrollIndicator【废弃】 | 是否显示水平滚动条 | boolean | true | | ||
| showsVerticalScrollIndicator 【废弃】 | 是否显示垂直滚动条 | boolean | true | | ||
| onEndReachedThreshold | 设置加载更多的偏移 | string | 500rem | | ||
| onEndReached | 滚动到底部时的事件( 距离底部 onEndReachedThreshold 长度时触发) | event | 无 | | ||
| scrollEventThrottle | 在滚动过程中,scroll 事件被调用的频率(默认值为 100),用于滚动的节流 | number | 100 | | ||
| onScroll | 滚动时触发的事件 | function | | ||
| style | 容器样式 | object | 无 | | ||
| contentContainerStyle | 容器内部 container 样式 | 无 | | ||
### resetLoadmore 实例方法 | ||
#### 实例方法 | ||
```js | ||
//调用 resetLoadmore 以保证上一次加载不到数据后,下次还能继续触发 onEndReached | ||
this.refs.scroller1.resetLoadmore(); | ||
- **resetLoadmore()** | ||
//省略部分代码 | ||
<ScrollView ref="scroller1" onEndReached={this.loadmore}> | ||
```js | ||
//调用 resetLoadmore 以保证上一次加载不到数据后,下次还能继续触发 onEndReached | ||
this.refs.scroller1.resetLoadmore(); | ||
//省略部分代码 | ||
<ScrollView ref="scroller1" onEndReached={this.loadmore}> | ||
{this.getViews()} | ||
</ScrollView>; | ||
``` | ||
</ScrollView>; | ||
``` | ||
这是一个重置 `onEndReached 是否能触发的` 标记位的方法。标记位默认为 true,即滚动到底部即可触发 onEndReached 事件。但**当 onEndReached 触发后,没有通过 setState 增加数据导致页面 scroller 内容变长,(或者反而变短了),native 端会将标记位设置为 false。** | ||
此时调用 resetLoadmore ,可以清除标记位,让 onEndReached 可以再次触发。 | ||
这是一个重置 `onEndReached 是否能触发的` 标记位的方法。标记位默认为 true,即滚动到底部即可触发 onEndReached 事件。但**当 onEndReached 触发后,没有通过 setState 增加数据导致页面 scroller 内容变长,(或者反而变短了),native 端会将标记位设置为 false。** | ||
此时调用 resetLoadmore ,可以清除标记位,让 onEndReached 可以再次触发。 | ||
- **scrollTo(options = { y: 0, animated: true})** | ||
当前 ScrollView 实例需要滚动到某个位置时,目前只支持纵向滚动 | ||
- options: | ||
- options.y : 位移偏移量,默认 0 | ||
- options.animated: 是否展示滑动动画 , 默认 true | ||
```js | ||
scrollTo = e => { | ||
this.refs.scroller1.scrollTo({ y : 100 }); | ||
}; | ||
render(){ | ||
return ( | ||
<ScrollView ref="scroller1" style={styles.scroller}> | ||
<View style={{ height: 400 }}></View> | ||
<View style={{ height: 400 }}></View> | ||
<View style={{ height: 400 }}></View> | ||
<Button onPress={this.scrollTo}> 滑动到 100rem </Button> | ||
</ScrollView> | ||
) | ||
} | ||
``` | ||
- **scrollToElement(ref,options = {offset:0, animated:true})** | ||
当前 ScrollView 实例需要把某个元素滚动到可视区域时 | ||
- ref : 元素实例 | ||
- options: | ||
- options.offset : 位移偏移量,默认 0 | ||
- options.animated: 是否展示滑动动画 , 默认 true | ||
```js | ||
scrollToElement = e => { | ||
this.refs.scroller1.scrollToElement(this.refs.specialView); | ||
}; | ||
render(){ | ||
return ( | ||
<ScrollView ref="scroller1" style={styles.scroller}> | ||
<View style={{ height: 400 }}></View> | ||
<View style={{ height: 400 }}></View> | ||
<View style={{ height: 400 }} ref="specialView"><Text> hi, I am special </Text></View> | ||
<View style={{ height: 400 }}></View> | ||
<Button onPress={this.scrollToElement}> 滑动到指定元素:ref = specialView </Button> | ||
</ScrollView> | ||
) | ||
} | ||
``` |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
13
94
49227
12
934
1