### RN组件
* * * * *
RN与React不同的是,它没有div/img/p...等组件,它有一些内置的常用组件。
#### 常用组件:
* Text(显示文本的React组件,并且它也支持嵌套、样式,以及触摸处理。)
* View(相当于div的职责)
* Image
* Button
* TextInput(输入框)
* ScrollView(滚动视图)
* FlatList(ListView已过时)-- 列表
* Modal模态框
* TouchableHighlight
* TouchableNativeFeedback
* TouchableOpacity
* TouchableWithoutFeedback
#### 支持onPress的组件
Text、TouchableHighlight、TouchableNativeFeedback、TouchableOpacity、TouchableWithoutFeedback
**Text**
显示文本的React组件,并且它也支持嵌套、样式,以及触摸处理。
~~~
<Text
numberOfLines={2} // 文本显示行数 多余...
onPress={()=>{alert(1)}} // 点击事件
onLongPress={()=>{alert('longPress')}} // 长按事件
selectable={true} // 是否可以选择文本
style={{color:'red',fontFamily:'',fontSize:14,fontWeight:200,lineHeight:20,textAlign:'center'}} // 样式
>
</Text>
~~~
| 嵌套 | Text标签里面可以嵌套Text标签 |
| --- | --- |
| 继承 | 子Text标签会且只会继承`父Text`标签的样式,除了Text外的组件将不会有文本属性 |
| 容器 | Text元素不使用flex布局,采用文本布局,它将不再是一个矩形容器,文字过长时会折叠 |
注意:Text里面可以嵌套View,但是View必须设置高度宽度。
由于不能直接设置一整颗子树的默认样式。但是又有很多样式重复的Text,可以每个Text指定同一个styles,或者创建一个包含相关样式的组件MyAppText。
**View**
创建UI时最基础的组件,View是一个支持Flexbox布局、样式、一些触摸处理、和一些无障碍功能的容器,并且它可以放到其它的视图里,也可以有任意多个任意类型的子视图。相当于是web里面的div的级别。
~~~
<View
accessibilityLabel={}
accessible={true}
onAccessibilityTap={()=>{}}
onLayout={()=>{}}
onMagicTap={()=>{}}
onMoveShouldSetResponder={()=>{}}
...
style={}
>
</View>
~~~
不能在View里面直接写文字,文字必须写在Text组件里面。平常View用到最多的就是布局,View的设计初衷是和StyleSheet搭配使用。
**Image**
~~~
// 静态图片资源
<Image source={require('./my-icon.png')} />
// 网络图片
<Image source={{uri: 'https://facebook.github.io/react/img/logo_og.png'}}
style={{width: 400, height: 400}} />
~~~
注意点:
| 静态图片 | require里面不能使用变量,一定要是静态字符串 |
| --- | --- |
| 网络图片 | 一定要设置width和height |
| 圆角边框 | borderRadius可以,但是borderTopLeftRadius,borderTopRightRadius,borderBottomLeftRadius,borderBottomRightRadius这四个属性在IOS上使用在Image组件上无效|
| 背景图片 | 有时候会用到图片背景,但Rn是没有background-image属性的,我们可以使用`ImageBackground`组件 |
| source是个object对象 | 未来可能会加入精灵图(sprites)的支持:在输出{uri: ...}的基础上,我们可以进一步输出裁切信息{uri: ..., crop: {left: 10, top: 50, width: 20, height: 40}},这样理论上就可以在现有的代码中无缝支持精灵图的切分。 |
**Button**
~~~
<Button
title="按钮"
color="#841584" // ios 文本的颜色 Android 按钮的背景色
accessibilityLabel="我会被读出来的文本" // 给残障人士显示的文本
onPress={()=>{alert("我是按钮")}}
/>
~~~
按钮颜色在IOS和Android上不统一,建议使用Touchable系列组件。
**TextInput**
TextInput是一个允许用户在应用中通过键盘输入文本的基本组件。本组件的属性提供了多种特性的配置,譬如自动完成、自动大小写、占位文字,以及多种不同的键盘类型(如纯数字键盘)等等。
~~~
<TextInput
style={{height: 50,borderWidth:1,borderColor:'#ccc'}}
onChange={()=>{}} // 改变值不会作为参数传递
onChangeText={(val)=>{this.setState({TextVal: val})}}
autoCapitalize='sentences' // 是否要自动将特定字符切换为大写
autoCorrect={true} // 是否关闭拼写自动修正
autoFocus={true} // 在componentDidMount后会获得焦点
maxLength={10} // 最多的字符数
multiline={false} // 是否多行
onBlur={()=>{alert('失去焦点')}}
onFocus={()=>{alert('获得焦点')}}
placeholder='请输入'
placeholderTextColor='#ccc'
value=''
/>
<Text>{this.state.TextVal}</Text>
~~~
| onChangeText | 从TextInput里取值这就是目前唯一的做法! |
| --- | --- |
**ScrollView**
ScrollView必须要有一个高度,或者设置`flex:1`,因为ScrollView是将一系列不确定高度的子组件装进一个确定高度的容器(通过滚动操作)。
~~~
<ScrollView
contentContainerStyle={styles.contentContainer}
horizontal={true} // true 横向滚动
keyboardDismissMode='none' // 滚动时隐藏键盘
onScroll={()=>{}} // 滚动函数
refreshControl={<View></View>} // 刷新的头组件
showsHorizontalScrollIndicator={false} // 横向滚动条
>
</ScrollView>
~~~
| ScrollView | ListView | FlatList |
| --- | --- | --- |
| 把所有子元素一次性全部渲染出来 | ListView会惰性渲染子元素,只在它们将要出现在屏幕中时开始渲染。 | 0.43版本开始新出的改进版的ListView,性能更优 |
**FlatList**
~~~
<FlatList data={this.state.courseList}
renderItem={this._renderCourse.bind(this)} // 循环渲染子组件
keyExtractor={(item, index) => item.courseId} // 设置唯一key值
/>
~~~
功能:
* 完全跨平台。
* 支持水平布局模式。
* 行组件显示或隐藏时可配置回调事件。
* 支持单独的头部组件。
* 支持单独的尾部组件。
* 支持自定义行间分隔线。
* 支持下拉刷新。
* 支持上拉加载。
* 支持跳转到指定行(ScrollToIndex)。
官网的一个例子:
~~~
class MyListItem extends React.PureComponent {
_onPress = () => {
this.props.onPressItem(this.props.id);
};
render() {
return (
<SomeOtherWidget
{...this.props}
onPress={this._onPress}
/>
)
}
}
class MyList extends React.PureComponent {
state = {selected: (new Map(): Map<string, boolean>)};
_keyExtractor = (item, index) => item.id;
_onPressItem = (id: string) => {
// updater functions are preferred for transactional updates
this.setState((state) => {
// copy the map rather than modifying state.
const selected = new Map(state.selected);
selected.set(id, !selected.get(id)); // toggle
return {selected};
});
};
_renderItem = ({item}) => (
<MyListItem
id={item.id}
onPressItem={this._onPressItem}
selected={!!this.state.selected.get(item.id)}
title={item.title}
/>
);
render() {
return (
<FlatList
data={this.props.data}
extraData={this.state}
keyExtractor={this._keyExtractor}
renderItem={this._renderItem}
/>
);
}
}
~~~
优化点:
| 每个item渲染的时候 | 1.onPressItem属性使用箭头函数而非bind的方式进行绑定,使其不会在每次列表重新render时生成一个新的函数,从而保证了props的不变性,不会触发自身无谓的重新render。2.如果你是用bind来绑定onPressItem,每次都会生成一个新的函数,导致props在===比较时返回false,从而触发自身的一次不必要的重新render。
| --- | --- |
| 指定extraData={this.state}属性 | 保证state.selected变化时,能够正确触发FlatList的更新。如果不指定此属性,则FlatList不会触发更新,因为它是一个PureComponent,其props在===比较中没有变化则不会触发更新。PureComponent仅仅是浅比较,即使对象内容改变了,它指向的还是同一个对象。 |
| keyExtractor | 指定使用id作为列表每一项的key |
PureComponent的shouldComponentUpdate:
~~~
if (this._compositeType === CompositeTypes.PureClass) {
shouldUpdate = !shallowEqual(prevProps, nextProps) || ! shallowEqual(inst.state, nextState); // 浅比较
}
~~~
[PureComponent的重要性和使用方式](http://www.zcfy.cc/article/why-and-how-to-use-purecomponent-in-react-js-60devs-2344.html)
**组件推荐:**
* [react-navigation](https://github.com/react-community/react-navigation) FB推荐导航组件
* [react-native-tab-navigator](https://github.com/happypancake/react-native-tab-navigator) Tab切换
* [react-native-scrollable-tab-view](https://github.com/skv-headless/react-native-scrollable-tab-view) Tab切换,每个tab有自己的ScrollView,可自定义tab样式
* [react-native-easy-toast](https://github.com/crazycodeboy/react-native-easy-toast)
* [react-native-image-picker](https://github.com/react-community/react-native-image-picker) 本地图片选择
* [react-native-vector-icons](https://github.com/oblador/react-native-vector-icons) 字体图标
* [react-native-swiper](https://github.com/leecade/react-native-swiper) 轮播图
* [react-native-storage](https://github.com/sunnylqm/react-native-storage) 基于AsyncStorage的本地存储
**组件封装:**
