一. 第一个应用: 天气小应用
import React, { Component } from "react";
import { StyleSheet, Text, View, TextInput, ImageBackground } from "react-native";
import Forecast from "./Forecast";
import OpenWeatherMap from "./open_weather_map";
class WeatherProject extends Component {
constructor(props) {
super(props);
this.state = { zip: "", forecast: null };
}
_handleTextChange = event => {
let zip = event.nativeEvent.text;
OpenWeatherMap.fetchForecast(zip).then(forecast => {
this.setState({ forecast: forecast });
});
};
render() {
let content = null;
if (this.state.forecast !== null) {
content = (
<Forecast
main={this.state.forecast.main}
description={this.state.forecast.description}
temp={this.state.forecast.temp}
/>
);
}
return (
<View style={styles.container}>
<ImageBackground
source={require("./flowers.png")}
resizeMode="cover"
style={styles.backdrop}
>
<View style={styles.overlay}>
<View style={styles.row}>
<Text style={styles.mainText}>
Current weather for
</Text>
<View style={styles.zipContainer}>
<TextInput
style={[styles.zipCode, styles.mainText]}
onSubmitEditing={this._handleTextChange}
underlineColorAndroid="transparent"
/>
</View>
</View>
{content}
</View>
</ImageBackground>
</View>
);
}
}
const baseFontSize = 16;
const styles = StyleSheet.create({
container: { flex: 1, alignItems: "center", paddingTop: 30 },
backdrop: { width:"100%",height:"100%" },
overlay: {paddingTop: 5,
backgroundColor: "#000000",
opacity: 0.5,
flexDirection: "column",
alignItems: "center"
},
row: {
flexDirection: "row",
flexWrap: "nowrap",
alignItems: "flex-start",
padding: 30
},
zipContainer: {
height: baseFontSize + 10,
borderBottomColor: "#DDDDDD",
borderBottomWidth: 1,
marginLeft: 5,
marginTop: 3
},
zipCode: { flex: 1, flexBasis: 1, width: 50, height: baseFontSize },
mainText: { fontSize: baseFontSize, color: "#FFFFFF" }
});
export default WeatherProject;
1.event.nativeEvent.text
(1)onChange:当文本发生变化时,调用该函数。
- 它的回调接收一个 event 参数,通过 event.nativeEvent.text 可以获取用户输入的字符串。
。
(2)onEndEditing:当结束编辑时,调用该函数。
- 它的回调接收一个 event 参数,通过 event.nativeEvent.text 可以获取用户输入的字符串。
(3)onBlur:失去焦点时触发(在 onEndEditing 之后)。
- 它的回调接收一个 event 参数,通过 event.nativeEvent.text 可以获取用户输入的字符串。
(4)onFocus:获得焦点时触发。
- 它的回调接收一个 event 参数,通过 event.nativeEvent.text 可以获取组件中的字符串(上次输入的,或者是程序设定的默认值)
(5)onSubmitEditing:当结束编辑后,点击键盘的提交按钮触发该事件。
- 它的回调接收一个 event 参数,通过 event.nativeEvent.text 可以获取用户输入的字符串。
2.{ width:"100%",height:"100%" } 宽高占页面的100%
二.
1.split() 方法用于把一个字符串分割成字符串数组。
str.split(' ' );是以空格拆分,差分后,行程结果的数组,数组的元素都为字符串。
str.split(' ',3); 是以空格拆分,拆分后,只取数组length为3的数组。
例如: this.state.text.split('#')[this.state.text.split('#').length - 1] 用 ‘#’ 字符拆分字符串,并取得数组的最后一个元素
2.map() 方法返回一个新数组,数组中的元素为原始数组元素调用函数处理后的值。
map() 方法按照原始数组元素顺序依次处理元素。
注意: map() 不会对空数组进行检测。
注意: map() 不会改变原始数组。
3.运算符 && ||
在运算过程中,首先js 会将 && 和|| 两边的值转成Boolean 类型,然后再算值 ,
&&运算如果返回true,则取后面的值,如果|| 返回true,则取前面的值 ,
而其中数值转换成boolean 的规则 是: 对象、非零整数、非空字符串返回true,其它为false ;
例如:该逻辑运算符支持短路原则 参考:http://blog.csdn.net/xiaoshuode/article/details/51612423
var a = “” || null || 3 || 4 —-> var a = false || false || true || true 结果为true 则返回第一个true,即是3
分析: || 这个运算符 “一真为真”,结果返回true,取前面的true(第一个true),即是 3
var b = 4 && 5 && null && 0 ——> var b = true && true && false && false 结果是false 则返回第一个false 即是null .
分析: && 这个运算符 “一假为假”,结果返回false,取前面的false(第一个false),即是 null
var c = 5 && 6 ----->var c = true && true 结果为ture,则返回后面的ture,即是 6
5.join() 方法用于把数组中的所有元素放入一个字符串。元素是通过指定的分隔符进行分隔的。
语法
arrayObject搜索.join(separator)
参数、描述
separator 可选。指定要使用的分隔符。如果省略该参数,则默认使用逗号作为分隔符。
返回值
返回一个字符串。该字符串是通过把 arrayObject 的每个元素转换为字符串,然后把这些字符串连接起来,在两个元素之间插入separator 字
符串而生成的。
三. react-navigation
// In App.js in a new project
import React from "react";
import { Button,View, Text } from "react-native";
import { createStackNavigator, createAppContainer } from "react-navigation";
class DetailsScreen extends React.Component {
render() {
return (
<View style={{ flex: 1, alignItems: "center", justifyContent: "center" }}>
<Text>Details Screen</Text>
</View>
);
}
}
class HomeScreen extends React.Component {
render() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Home Screen</Text>
<Button
title="Go to Details"
onPress={() => this.props.navigation.navigate('Details')}
/>
</View>
);
}
}
const AppNavigator = createStackNavigator(
{
Home: HomeScreen,
Details: DetailsScreen
},
{
initialRouteName: "Home"
}
);
const AppContainer = createAppContainer(AppNavigator);
export default class App extends React.Component {
render() {
return <AppContainer />;
}
}
1. 每个页面可用一个class定义 ,class名为路由到的名字(键值对中的值), 而navigate方法调用的为键值对中的键
2.this.props.navigation.navigate('RouteName') `将新路由推送到堆栈导航器,如果它尚未在堆栈中,则跳转到该页面。
3.使用` this.props.navigation.popToTop() `返回堆栈中的第一个页面。
4.生命周期??????
5.传递参数
<Button
title="Go to Details... again"
onPress={() =>
this.props.navigation.navigate('Details', {
itemId: 86,
otherParam: 'anything you want here',
})}
/>
6.读取参数
const otherParam = navigation.getParam('otherParam', 'some default value');
第一个参数是要读的值,第二个参数是缺省值
你也可以直接使用this.props.navigation.state.params
访问 params 对象。 如果没有提供参数,这可能是null
,所以使用getParam
通常更容易,所以你不必处理这种情况。
(2)
设置标题栏显示的标题
每个页面组件可以有一个名为navigationOptions
的静态属性,它是一个对象或一个返回包含各种配置选项的对象的函数。 我们用于设置标题栏的标题的是title
这个属性,如以下示例所示。
class HomeScreen extends React.Component {
static navigationOptions = {
title: 'Home',
};
/* render function, etc */
}
class DetailsScreen extends React.Component {
static navigationOptions = {
title: 'Details',
};
/* render function, etc */
}
在标题中使用参数
为了在标题中使用参数,我们需要使navigationOptions
成为一个返回配置对象的函数。 尝试在navigationOptions
中使用this.props
可能很诱人,但因为它是组件的静态属性,所以this
不会指向一个组件的实例,因此没有 props 可用。 相反,如果我们将navigationOptions
作为一个函数,那么React Navigation将会用包含{navigation> navigationOptions,screenProps}
的对象调用它 -- 在这种情况下,我们只用关心navigation
,它是与传递给页面的this.props.navigation </ code>相同的对象。 您可能还记得,我们可以通过<code> navigation.state.params
从navigation
中获取参数,因此我们执行下面的操作以提取 param 并将其用作标题。
class DetailsScreen extends React.Component {
static navigationOptions = ({ navigation }) => {
return {
title: navigation.getParam('otherParam', 'A Nested Details Screen'),
};
};
/* render function, etc */
}
跨页面共享通用的navigationOptions
通常我们希望可以在多个页面上以类似的方式配置标题栏。 例如,你公司的品牌颜色可能为红色,因此你希望标题栏背景颜色为红色,色调为白色。 方便的是,这些只是我们正在使用的运行示例的颜色,并且你会注意到,当你导航到DetailsScreen
时,颜色会恢复默认值。 如果在我们应用中每个页面上,都必须,像将navigationOptions
的标题栏样式属性从HomeScreen
复制到DetailsScreen
一样,那是不是非常的糟糕? 谢天谢地,我们并没有这么做。 我们可以将配置移动到` defaultNavigationOptions </ code>属性下的 stack navigator 中。
const RootStack = createStackNavigator(
{
Home: HomeScreen,
Details: DetailsScreen,
},
{
initialRouteName: 'Home',
/* The header config from HomeScreen is now here */
defaultNavigationOptions: {
headerStyle: {
backgroundColor: '#f4511e',
},
headerTintColor: '#fff',
headerTitleStyle: {
fontWeight: 'bold',
},
},
}
);
`
覆盖共享的navigationOptions
你的页面组件上指定的navigationOptions
与其父级 stack navigator 中的navigationOptions
一起合并时,页面组件上的选项优先。 让我们使用这些知识点在Details
页面上反转背景和色彩。
使用自定义组件替换标题
有时候,你可能需要更多的控制权,而不仅仅是改变标题的文本和样式 -- 例如,你可能想在标题所在的位置放置一张图片,或者将标题变为按钮。 在这些情况下,你可以完全覆盖用于标题的组件并提供您自己的组件。
class LogoTitle extends React.Component {
render() {
return (
<Image
source={require('./spiro.png')}
style={{ width: 30, height: 30 }}
/>
);
}
}
class HomeScreen extends React.Component {
static navigationOptions = {
// headerTitle instead of title
headerTitle: <LogoTitle />,
};
/* render function, etc */
}
您可能想知道,为什么headerTitle
能够支持我们设置一个组件,而不是像以前一样设置一个title
? 原因是headerTitle
是一个特定于 stack navigator 的属性,headerTitle
默认为一个Text
组件,它显示title
这个字符串。
标题栏和其所属的页面之间的交互
最常用的模式是在组件实例上提供按钮访问函数 params
。 我们将用一个经典的例子--计数器,来演示:
class HomeScreen extends React.Component {
static navigationOptions = ({ navigation }) => {
return {
headerTitle: <LogoTitle />,
headerRight: (
<Button
onPress={navigation.getParam('increaseCount')}
title="+1"
color="#fff"
/>
),
};
};
componentDidMount() {
this.props.navigation.setParams({ increaseCount: this._increaseCount });
}
state = {
count: 0,
};
_increaseCount = () => {
this.setState({ count: this.state.count + 1 });
};
/* later in the render function we display the count */
}
import React from 'react';
import { Text, View } from 'react-native';
import { createBottomTabNavigator, createAppContainer } from 'react-navigation';
import Ionicons from 'react-native-vector-icons/Ionicons';
class HomeScreen extends React.Component {
render() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Home!</Text>
</View>
);
}
}
class SettingsScreen extends React.Component {
render() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Settings!</Text>
</View>
);
}
}
const TabNavigator = createBottomTabNavigator({
Home: HomeScreen,
Settings: SettingsScreen,
},
{
defaultNavigationOptions: ({ navigation }) => ({
tabBarIcon: ({ focused, horizontal, tintColor }) => {
const { routeName } = navigation.state;
let IconComponent = Ionicons;
let iconName;
if (routeName === 'Home') {
iconName = `ios-information-circle${focused ? '' : '-outline'}`;
// Sometimes we want to add badges to some icons.
// You can check the implementation below.
IconComponent = HomeIconWithBadge;
} else if (routeName === 'Settings') {
iconName = `ios-options`;
}
// You can return any component that you like here!
return <IconComponent name={iconName} size={25} color={tintColor} />;
},
}),
tabBarOptions: {
activeTintColor: 'tomato',
inactiveTintColor: 'gray',
},
}
);
export default createAppContainer(TabNavigator);
tabBarIcon
是navigationOptions
上的一个属性,所以我们知道我们可以在我们的页面上使用它,但在这种情况下,选择将它放在createBottomTabNavigator
的配置中,是为了方便集中配置图标。tabBarIcon
是一个给定focused
state、tintColor
和horizontal
等参数的函数 如果你在配置中进一步查看,您将看到tabBarOptions
、activeTintColor
和inactiveTintColor
。 这些默认为 iOS 平台的默认值,但您可以在这里更改它们。 传递给tabBarIcon
的tintColor
取决于focused
这个 state (判断该 Tab 是否获得了焦点),可以是活动,也可以是非活动状态。 当设备处于横屏时,horizontal
是true
;否则就是false
。- 有关
createBottomTabNavigator
配置选项的更多信息,请阅读完整API参考。
四. 一些反复出现的问题
(1) 箭头函数
x => x * x
上面的箭头函数相当于:
function (x) {
return x * x;
}
箭头函数相当于匿名函数,并且简化了函数定义。箭头函数有两种格式,一种像上面的,只包含一个表达式,连{ ... }
和return
都省略掉了。还有一种可以包含多条语句,这时候就不能省略{ ... }
和return
:
x => {
if (x > 0) {
return x * x;
}
else {
return - x * x;
}
}
如果参数不是一个,就需要用括号()
括起来:
// 两个参数:
(x, y) => x * x + y * y
// 当只有一个参数时,圆括号是可选的:
(单一参数) => {函数声明}
单一参数 => {函数声明}
// 无参数:
() => 3.14
// 可变参数:
(x, y, ...rest) => {
var i, sum = x + y;
for (i=0; i<rest.length; i++) {
sum += rest[i];
}
return sum;
}
如果要返回一个对象,就要注意,如果是单表达式,这么写的话会报错:
// SyntaxError:
x => { foo: x }
因为和函数体的{ ... }
有语法冲突,所以要改为:
// ok:
x => ({ foo: x })
(2) this
先理解普通JavaScript 的this 事件
- 当一个函数没有明确的调用对象的时候,也就是单纯作为独立函数调用的时候,将对函数的this使用默认绑定:绑定到全局的window对象
- 当函数被一个对象“包含”的时候,我们称函数的this被隐式绑定到这个对象里面了,这时候,通过this可以直接访问所绑定的对象里面的其他属性,比如下面的a属性
var obj = { a:1,
fire:function() {
console.log(this.a)
}}
obj.fire(); //输出1
// fire函数并不会因为它被定义在obj对象的内部和外部而有任何区别,也就是说在上述隐式绑定的两种形式下,fire通过this还是可以访问到obj内的a属性,这告诉我们:this是动态绑定的,或者说是在代码运行期绑定而不是在书写期
function
fire () {
console.log(this.a)
}
var obj = {a:1,fire:fire }
obj.fire(); // 输出1
-
2. 函数于对象的独立性, this的传递丢失问题
在上文中,函数虽然被定义在对象的内部中,但它和“在对象外部声明函数,然后在对象内部通过属性名称的方式取得函数的引用”,这两种方式在性质上是等价的(而不仅仅是效果上)
定义在对象内部的函数只是“恰好可以被这个对象调用”而已,而不是“生来就是为这个对象所调用的”)
var obj = { a:1, //a是定义在对象obj中的属性 1
fire:function() {
console.log(this.a)}
}
var
a = 2; //a是定义在全局环境中的变量 2
var fireInGrobal = obj.fire;
fireInGrobal(); // 输出 2 这个于obj中的fire函数的引用( fireInGrobal)在调用的时候,行为表现(输出)完全看不出来它就是在obj内部定义的,其原因在于:我们隐式绑定的this丢失了!! 从而 fireInGrobal调用的时候取得的this不是obj,而是window
3.在一串对象属性链中,this绑定的是最内层的对象
所以根据以上可知,由于JavaScript函数对this
绑定的错误处理,下面的例子无法得到预期结果:
var obj = {
birth: 1990,
getAge: function () {
var b = this.birth; // 1990
var fn = function () {
return new Date().getFullYear() - this.birth; // this指向window或undefined
};
return fn();
}
};
ES6的箭头函数,这里可以看出箭头函数中访问的this实际上是其父级作用域中的this(箭头函数相当于一个function,看箭头函数上一个function然后相当于正常的this理解),箭头函数本身的this是不存在的,这样就相当于箭头函数的this是在声明的时候就确定了(因为相当于作用域嘛)
var obj = {
age: 1,
say: function() {
setTimeout(function() {
console.log(this, this.age); // window undefined
}, 0);
},
}
var obj1 = {
age: 1,
say: function() {
setTimeout(() => {
console.log(this, this.age); // obj1 1
}, 0);
}
};
var obj = {
i: 10,
b: () => console.log(this.i, this),
c: function() {
console.log( this.i, this)
}
}
obj.b();
// undefined, Window{...}
obj.c();
// 10, Object {...}