ReactNative基础

一、基础

Props 属性

  • 用于定制组件的参数称为属性props
  • style source就是属性
  • ios 上使用http连接图片不会显示
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
export default class Bananas extends Component {
render() {
let pic = {
uri: 'https://upload.wikimedia.org/wikipedia/commons/d/de/Bananavarieties.jpg'
};
return (
<Image source={pic} style={{width: 193, height: 110}} />
// {pic} {}内部为一个变量或一个表达式 执行后取值
);
}
}

// 自定义的组件也可以使用props 只需在render函数中引用this.props
class Greeting extends Component {
render() {
return (
<View style={{alignItems: 'center'}}>
<Text>Hello {this.props.name}!</Text>
</View>
);
}
}
export default class LotsOfGreetings extends Component {
render() {
return (
<View style={{alignItems: 'center'}}>
<Greeting name='Rexxar' />
<Greeting name='Jaina' />
<Greeting name='Valeera' />
</View>
);
}
}

State 状态

  • 两种数据来控制一个组件:props和state
  • props是在父组件中指定,而且一经指定,在被指定的组件的生命周期中则不再改变
  • 对于需要改变的数据,我们需要使用state
1
2
3
4
5
6
7
8
9
10
11
12
class Blink extends Component {
constructor(props) {
super(props);
this.state = { isShowingText: true };

// 每1000毫秒对showText状态做一次取反操作
setInterval(() => {
this.setState(previousState => {
return { isShowingText: !previousState.isShowingText };
});
}, 1000);
}
  • 一切界面变化都是状态state变化
  • state的修改必须通过setState()方法
    • this.state.likes = 100; // 这样的直接赋值修改无效!
    • setState 是一个 merge 合并操作,只修改指定属性,不影响其他属性
    • setState 是异步操作,修改不会马上生效

样式

  • 核心组件都接受名为style的属性,JS 的语法要求使用了驼峰命名法
  • StyleSheet.create来集中定义组件的样式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
export default class LotsOfStyles extends Component {
render() {
return (
<View>
<Text style={styles.red}>just red</Text>
<Text style={styles.bigblue}>just bigblue</Text>
<Text style={[styles.bigblue, styles.red]}>bigblue, then red</Text>
<Text style={[styles.red, styles.bigblue]}>red, then bigblue</Text>
</View>
);
}
}

const styles = StyleSheet.create({
bigblue: {
color: 'blue',
fontWeight: 'bold',
fontSize: 30,
},
red: {
color: 'red',
},
});

高度与宽度

指定宽高

RN 中的尺寸都是无单位的,表示的是与设备像素密度无关的逻辑像素点

1
2
3
4
5
6
7
8
9
10
11
export default class FixedDimensionsBasics extends Component {
render() {
return (
<View>
<View style={{width: 50, height: 50, backgroundColor: 'powderblue'}} />
<View style={{width: 100, height: 100, backgroundColor: 'skyblue'}} />
<View style={{width: 150, height: 150, backgroundColor: 'steelblue'}} />
</View>
);
}
}

弹性(Flex)宽高

  • flex:1来指定某个组件扩张以撑满所有剩余的空间
  • 有多个并列的子组件使用了flex:1,则这些子组件会平分父容器中剩余的空间
  • 这些并列的子组件的flex值不一样,则谁的值更大,谁占据剩余空间的比例就更大
1
2
3
4
5
6
7
8
9
10
11
12
13
14
export default class FlexDimensionsBasics extends Component {
render() {
return (
// 试试去掉父View中的`flex: 1`。
// 则父View不再具有尺寸,因此子组件也无法再撑开。
// 然后再用`height: 300`来代替父View的`flex: 1`试试看?
<View style={{flex: 1}}>
<View style={{flex: 1, backgroundColor: 'powderblue'}} />
<View style={{flex: 2, backgroundColor: 'skyblue'}} />
<View style={{flex: 3, backgroundColor: 'steelblue'}} />
</View>
);
}
}

使用Flexbox布局

  • 使用 flexDirection alignItems justifyContent 三个样式属性就已经能满足大多数布局需求

flexDirection 布局的主轴

1
2
style={{flexDirection: 'row' }} 水平轴
style={{flexDirection: 'column' }} 竖直轴 默认
1
2
3
4
5
<View style={{flex: 1, flexDirection: 'row'}}>
<View style={{width: 50, height: 50, backgroundColor: 'powderblue'}} />
<View style={{width: 50, height: 50, backgroundColor: 'skyblue'}} />
<View style={{width: 50, height: 50, backgroundColor: 'steelblue'}} />
</View>

justifyContent 排列方式

flex-start、center、flex-end、space-around、space-between以及space-evenly

1
2
3
4
5
6
7
8
9
<View style={{
flex: 1,
flexDirection: 'row',
justifyContent: 'center',
}}>
<View style={{width: 50, height: 50, backgroundColor: 'powderblue'}} />
<View style={{width: 50, height: 50, backgroundColor: 'skyblue'}} />
<View style={{width: 50, height: 50, backgroundColor: 'steelblue'}} />
</View>

alignItems 决定其子元素沿着次轴的排列方式

flex-start、center、flex-end以及stretch

1
2
3
4
5
6
7
8
9
10
<View style={{
flex: 1,
flexDirection: 'column',
justifyContent: 'center',
alignItems: 'stretch',
}}>
<View style={{width: 50, height: 50, backgroundColor: 'powderblue'}} />
<View style={{height: 50, backgroundColor: 'skyblue'}} />
<View style={{height: 100, backgroundColor: 'steelblue'}} />
</View>

处理文本输入 TextInput

  • onChangeText 函数会在文本变化时被调用
  • onSubmitEditing的属性,会在文本被提交后(用户按下软键盘上的提交键)调用
1
2
3
4
5
6
7
8
9
10
<View style={{padding: 10}}>
<TextInput
style={{height: 40}}
placeholder="Type here to translate!"
onChangeText={(text) => this.setState({text})}
/>
<Text style={{padding: 10, fontSize: 42}}>
{this.state.text.split(' ').map((word) => word && '🍕').join(' ')}
</Text>
</View>

处理触摸事件

显示一个简单的按钮

Button是一个简单的跨平台的按钮组件

1
2
3
4
5
6
<Button
onPress={() => {
Alert.alert("你点击了按钮!");
}}
title="点我!"
/>

Touchable 系列组件

  • 一般来说,你可以使用TouchableHighlight来制作按钮或者链接。注意此组件的背景会在用户手指按下时变暗。
  • 在 Android 上还可以使用TouchableNativeFeedback,它会在用户手指按下时形成类似墨水涟漪的视觉效果。
  • TouchableOpacity会在用户手指按下时降低按钮的透明度,而不会改变背景的颜色。
  • 如果你想在处理点击事件的同时不显示任何视觉反馈,则需要使用TouchableWithoutFeedback。
  • https://v.youku.com/v_show/id_XMTQ5OTE3MjkzNg==.html?f=26822355&from=y1.7-1.3

使用滚动视图 ScrollView

  • ScrollView是一个通用的可滚动的容器
  • 通过horizontal属性来设置
  • 适合用来显示数量不多的滚动元素
    1
    2
    3
    4
    5
    6
    7
    8
    9
    export default class IScrolledDownAndWhatHappenedNextShockedMe extends Component {
    render() {
    return (
    <ScrollView>
    //...
    </ScrollView>
    );
    }
    }

    使用长列表 ScrollView

  • 适用于展示长列表数据的组件
  • 和ScrollView不同的是,FlatList并不立即渲染所有元素,而是优先渲染屏幕上可见的元素
  • 必须的两个属性是data和renderItem。data是列表的数据源,而renderItem则从数据源中逐个解析数据,然后返回一个设定好格式的组件来渲染。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
export default class FlatListBasics extends Component {
render() {
return (
<View style={styles.container}>
<FlatList
data={[
{key: 'Devin'},
{key: 'Jackson'},
{key: 'James'},
{key: 'Joel'},
{key: 'John'},
{key: 'Jillian'},
{key: 'Jimmy'},
{key: 'Julie'},
]}
renderItem={({item}) => <Text style={styles.item}>{item.key}</Text>}
/>
</View>
);
}
}

要渲染的是一组需要分组的数据,也许还带有分组标签的,那么SectionList将是个不错的选择

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
export default class SectionListBasics extends Component {
render() {
return (
<View style={styles.container}>
<SectionList
sections={[
{title: 'D', data: ['Devin']},
{title: 'J', data: ['Jackson', 'James', 'Jillian', 'Jimmy', 'Joel', 'John', 'Julie']},
]}
renderItem={({item}) => <Text style={styles.item}>{item}</Text>}
renderSectionHeader={({section}) => <Text style={styles.sectionHeader}>{section.title}</Text>}
keyExtractor={(item, index) => index}
/>
</View>
);
}
}

网络

使用Fetch

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
fetch("https://mywebsite.com/endpoint/", {
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json"
},
body: JSON.stringify({
firstParam: "yourValue",
secondParam: "yourOtherValue"
})
});

export default class FetchExample extends React.Component {

constructor(props){
super(props);
this.state ={ isLoading: true}
}

componentDidMount(){
return fetch('https://facebook.github.io/react-native/movies.json')
.then((response) => response.json())
.then((responseJson) => {

this.setState({
isLoading: false,
dataSource: responseJson.movies,
}, function(){

});

})
.catch((error) =>{
console.error(error);
});
}

WebSocket 支持

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
var ws = new WebSocket("ws://host.com/path");

ws.onopen = () => {
// connection opened
ws.send("something"); // send a message
};

ws.onmessage = e => {
// a message was received
console.log(e.data);
};

ws.onerror = e => {
// an error occurred
console.log(e.message);
};

ws.onclose = e => {
// connection closed
console.log(e.code, e.reason);
};

二、进阶

组件和API

基础组件

View Text Image TextInput ScrollView StyleSheet

交互控件

Button Picker Slider Switch

列表视图

FlatList 高性能滚动列表
SectionList 比前者多了分组

Platform 模块

React Native 提供了一个检测当前运行平台的模块。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import { Platform, StyleSheet } from "react-native";

// 样式
const styles = StyleSheet.create({
height: Platform.OS === "ios" ? 200 : 100
});
const styles = StyleSheet.create({
container: {
flex: 1,
...Platform.select({
ios: {
backgroundColor: "red"
},
android: {
backgroundColor: "blue"
}
})
}
});

// 组件
const Component = Platform.select({
ios: () => require("ComponentIOS"),
android: () => require("ComponentAndroid")
})();

<Component />;

使用导航器跳转页面

  • 只针对 iOS 平台开发 可以选择NavigatorIOS
  • 同时在iOS和Android上达到看起来像原生 原生导航: react-native-navigation

图片

静态图片资源

  • require 中的图片名字必须是一个静态字符串
1
2
3
<Image source={require('./my-icon.png')} />
// Packager 就会去这个组件所在的文件夹下查找 my-icon.png。并且,如果你有my-icon.ios.png和my-icon.android.png,Packager 就会根据平台而选择不同的文件。
// 还可以使用@2x,@3x这样的文件名后缀,来为不同的屏幕精度提供图片。

静态的非图片资源

require语法也可以用来静态地加载你项目中的声音、视频或者文档文件。大多数常见文件类型都支持,包括.mp3, .wav, .mp4, .mov, .htm 和 .pdf等

使用混合 App 的图片资源

  • 编写一个混合 App,原生+RN ,放置在 Xcode 的 asset 类目中,或是放置在 Android 的 drawable 目录里。
  • 注意此时只使用文件名,不带路径也不带后缀
1
2
3
4
// IOS
<Image source={{uri: 'app_icon'}} style={{width: 40, height: 40}} />
// Android
<Image source={{uri: 'asset:/app_icon.png'}} style={{width: 40, height: 40}} />

网络图片

需要手动指定图片的尺寸

1
2
3
4
5
6
// 正确
<Image source={{uri: 'https://facebook.github.io/react/logo-og.png'}}
style={{width: 400, height: 400}} />

// 错误
<Image source={{uri: 'https://facebook.github.io/react/logo-og.png'}} />

动画

React Native 提供了两个互补的动画系统:用于创建精细的交互控制的动画Animated和用于全局的布局动画LayoutAnimation