如何迈出第二步(组件优化)

真的这种事情很好,勇敢的迈出第一步之后,就必须要接着走下去了。因为我第一篇的文章已经发出去了,并在结尾说下一次要做优化,为了厚脸皮也要用心的把问题解决了。解决完问题之后,还要装个逼,装逼到一半的时候,装不下去了,就必须得继续学习才能继续装逼。希望大家可以勇敢的迈出惧怕或者懒散的一步,程序员不要眼高手低。谁说高手组队不会翻车?不仅仅是这样,越牛逼的人翻车的后果越严重。

接着上一篇比较破的文章(我确实是第一天开始写RN的代码,之前都是看),发文章的时候我甚至有点脸红,妈的这是第一次,觉得这么坑的文章要发出去了,但是随之带来的就是写好下一篇的思想。不啰嗦,开始写:

上节最后的优化,是把pageControl用for循环写了,然后我们先在最小的组件中看下有没有可以优化的地方。PageControl.js中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
const styles = StyleSheet.create({
container: {
backgroundColor: 'white',
flexDirection: 'row',
alignItems: 'center',
justifyContent: "space-between",
width: 50,
marginTop: 40
},
item: {
width: 10,
height: 10,
borderRadius: 5,
backgroundColor: 'white',
borderColor: '#34a3ff',
borderWidth: 1
},
itemHighLight: {
width: 10,
height: 10,
borderRadius: 5,
backgroundColor: 'skyblue'
}
});

css写重复了,我们提取相同的:

1
2
3
4
5
6
7
8
9
10
11
12
13
itemSize: {
width: 10,
height: 10,
borderRadius: 5,
},
item: {
backgroundColor: 'white',
borderColor: '#34a3ff',
borderWidth: 1
},
itemHighLight: {
backgroundColor: 'skyblue'
}

然后将render()方法中不会改变的局部变量用let定义:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
render() {
let number = this.props.number;
let index = this.props.index;
var items = new Array();
for (var i=0; i<number; i++) {
let item = (
<View style={[(i == index ? styles.itemHighLight : styles.item), styles.itemSize]} key={i} ></View>
);
items.push(item);
}
return (
<View style={styles.container}>
{items}
</View>
)
}

然后想一个问题,如何可以让PageControl保持不跟着ScrollView一起滚动呢(我们现在相当于创建了3个PageControl)?所以这里PageControl组件要提供一个动态修改当前index的功能。所以scrollView的滑动我们要监听,然后在状态中加入当前的页码。这个时候我们会发现,PageControl与下边的进入按钮其实是不动的,所以我们将index.ios.js中的内容再次拆分为上下两部分,上边显示内容,下边显示pageControl与进入按钮。这个时候,程序要大改了,貌似之前写的都有问题,但是别急,慢慢来看,我们就是将东西诺了个位置。

既然让pageControl不动,所以只能使用position: 'absolute'来帮助它脱离当前的文档流(当前的视图层),并且要实时的控制pageControl的展示,所以在index.ios.js中的state中加入currentIndex属性,并监听scrollView的滑动。最终我们的PageControl:

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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
import React, { Component, } from 'react'
import { View, StyleSheet, Dimensions } from 'react-native'
class PageControl extends Component {
static propTypes = {}
static defaultProps = {}
constructor(props) {
super(props)
this.state = {}
}
render() {
let number = this.props.number;
let index = this.props.index;
var items = new Array();
let screenWidth = Dimensions.get('window').width;
let containerPosition = {
width: number * 20,
position: 'absolute',
left: (screenWidth - number * 20) / 2.0,
top: this.props.top
};
for (var i=0; i<number; i++) {
let item = (
<View style={[(i == index ? styles.itemHighLight : styles.item), styles.itemSize]} key={i} ></View>
);
items.push(item);
}
return (
<View style={[styles.container, containerPosition]}>
{items}
</View>
)
}
}
const styles = StyleSheet.create({
container: {
backgroundColor: 'white',
flexDirection: 'row',
alignItems: 'center',
justifyContent: "space-between",
width: 50,
marginTop: 40
},
itemSize: {
width: 10,
height: 10,
borderRadius: 5,
},
item: {
backgroundColor: 'white',
borderColor: '#34a3ff',
borderWidth: 1
},
itemHighLight: {
backgroundColor: 'skyblue'
}
});
export default PageControl

再看一下ScrollContent:

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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
import React, { Component, } from 'react'
import {
View,
StyleSheet,
Image,
Text,
Dimensions
} from 'react-native'
class ScrollContent extends Component {
static propTypes = {}
static defaultProps = {}
constructor(props) {
super(props)
this.state = {}
}
render() {
return (
<View style={ styles.container }>
<Image source={{ uri: this.props.uri }} style={ styles.image }/>
<Text style={styles.title}>{this.props.title}</Text>
<Text style={styles.detail}>{this.props.detail}</Text>
<Text style={styles.subDetail}>{this.props.subDetail}</Text>
</View>
)
}
}
const contentWidth = Dimensions.get('window').width;
const contentHeight = Dimensions.get('window').height;
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: "center",
backgroundColor: 'white',
width: contentWidth,
height: contentHeight
},
image: {
width: 253,
height: 200
},
title: {
fontSize: 24,
color: '#358ED7',
fontWeight: "400",
marginTop: 50
},
detail: {
fontSize: 14,
color: '#1D1D26',
fontWeight: "400",
marginTop: 20
},
subDetail: {
fontSize: 14,
color: '#1D1D26',
fontWeight: "400",
marginTop: 2
}
});
export default ScrollContent

index.ios.js中我们顺便把初始化content的地方改掉,并且在最后一张的时候展示进入App按钮:

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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
import React, { Component } from 'react';
import { AppRegistry, StyleSheet, View, ScrollView, TouchableOpacity, Dimensions, Text} from 'react-native';
import ScrollContent from './ScrollContent';
import PageControl from './PageControl';
class Project extends Component {
constructor(props) {
super(props)
this.state = { currentIndex: 0 };
}
render() {
let screenWidth = Dimensions.get('window').width;
let pageControlTop = screenWidth / 2.0 + 300;
let objects = [
{
uri: "http://ocef2grmj.bkt.clouddn.com/Group.png",
title: "Shopping directly",
detail: "Know your factories. Know your costs.",
subDetail: "Always ask why."
},
{
uri: "http://ocef2grmj.bkt.clouddn.com/Clothes-illustration.png",
title: "Hello world!",
detail: "Know your factories. Know your costs.",
subDetail: "Always ask why."
},
{
uri: "http://ocef2grmj.bkt.clouddn.com/Group1.png",
title: "What are you doing?",
detail: "Know your factories. Know your costs.",
subDetail: "Always ask why."
}
];
var scrollItems = new Array();
for (var i=0; i<objects.length; i++) {
let obj = objects[i];
let item = (
<ScrollContent uri={obj.uri} title={obj.title} detail={obj.detail} subDetail={obj.subDetail} key={i}/>
);
scrollItems.push(item);
}
return (
<View style={styles.container}>
<ScrollView
style={styles.scrollView}
horizontal={true}
showsHorizontalScrollIndicator={false}
alwaysBounceHorizontal={true}
pagingEnabled={true}
onScroll={(event: Object) => {
let caluIndex = parseInt(event.nativeEvent.contentOffset.x / screenWidth);
this.setState({ currentIndex: caluIndex });
}}
>
{scrollItems}
</ScrollView>
<PageControl number={objects.length} index={this.state.currentIndex} top={pageControlTop}/>
<TouchableOpacity onPress={() => {}} activeOpacity={50 / 100}>
{
this.state.currentIndex == objects.length - 1 ?
(<Text style={ styles.enterButton }>Enter</Text>): (null)
}
</TouchableOpacity>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1
},
scrollView: {
flex: 1,
backgroundColor: 'white'
},
enterButton: {
position: 'absolute',
left: (Dimensions.get('window').width - 70) / 2.0,
bottom: 15,
color: '#34A3FF',
fontSize: 17,
fontWeight: "400",
borderWidth: 1,
borderColor: '#34A3FF',
borderRadius: 3,
padding: 5,
paddingLeft: 15,
paddingRight: 15,
}
});
AppRegistry.registerComponent('Project', () => Project);

接下来,我们要把这个ScrollView单开一个叫做引导页的组件GuidePage.js:

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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
import React, { Component, } from 'react'
import { View, ScrollView, TouchableOpacity, Dimensions, Text, StyleSheet } from 'react-native'
import ScrollContent from './ScrollContent';
import PageControl from './PageControl';
class GuidePage extends Component {
constructor(props) {
super(props)
this.state = { currentIndex: 0 };
}
render() {
let screenWidth = Dimensions.get('window').width;
let pageControlTop = screenWidth / 2.0 + 300;
let objectNum = this.props.objects.length;
var scrollItems = new Array();
for (var i=0; i<objectNum; i++) {
let obj = this.props.objects[i];
let item = (
<ScrollContent uri={obj.uri} title={obj.title} detail={obj.detail} subDetail={obj.subDetail} key={i}/>
);
scrollItems.push(item);
}
return (
<View style={styles.container}>
<ScrollView
style={styles.scrollView}
horizontal={true}
showsHorizontalScrollIndicator={false}
alwaysBounceHorizontal={true}
pagingEnabled={true}
onScroll={(event: Object) => {
let caluIndex = parseInt(event.nativeEvent.contentOffset.x / screenWidth);
this.setState({ currentIndex: caluIndex });
}}
>
{scrollItems}
</ScrollView>
<PageControl number={objectNum} index={this.state.currentIndex} top={pageControlTop}/>
<TouchableOpacity onPress={() => {}} activeOpacity={50 / 100}>
{
this.state.currentIndex == objectNum - 1 ?
(<Text style={ styles.enterButton }>Enter</Text>): (null)
}
</TouchableOpacity>
</View>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1
},
scrollView: {
flex: 1,
backgroundColor: 'white'
},
enterButton: {
position: 'absolute',
left: (Dimensions.get('window').width - 70) / 2.0,
bottom: 15,
color: '#34A3FF',
fontSize: 17,
fontWeight: "400",
borderWidth: 1,
borderColor: '#34A3FF',
borderRadius: 3,
padding: 5,
paddingLeft: 15,
paddingRight: 15,
}
});
export default GuidePage

然后在使用的时候index.ios.js

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
37
38
39
40
41
42
43
import React, { Component } from 'react';
import { AppRegistry, StyleSheet, View} from 'react-native';
import GuidePage from './GuidePage';
class Project extends Component {
render() {
let objects = [
{
uri: "http://ocef2grmj.bkt.clouddn.com/Group.png",
title: "Shopping directly",
detail: "Know your factories. Know your costs.",
subDetail: "Always ask why."
},
{
uri: "http://ocef2grmj.bkt.clouddn.com/Clothes-illustration.png",
title: "Hello world!",
detail: "Know your factories. Know your costs.",
subDetail: "Always ask why."
},
{
uri: "http://ocef2grmj.bkt.clouddn.com/Group1.png",
title: "What are you doing?",
detail: "Know your factories. Know your costs.",
subDetail: "Always ask why."
}
];
return (
<View style={styles.container}>
<GuidePage objects={objects} />
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1
}
});
AppRegistry.registerComponent('Project', () => Project);

这样,我们解决了引导页的封装,第一次入手,确实绕弯,道行不深啊。不急慢慢来,既然有了引导页,就要点击进入的时候跳转到App中,这个操作如何来完成呢?我们知道,index.ios.js是我们程序的入口,而且引导页只出现一次,我们下篇文章来摸索一下。

代码的地址还没变哦,在迈出第一步中文末有。

评论