React Native - 组件
概述
组件样式
在React Native中,仍然使用JavaScript来写样式。所有的核心组件都接受名为style的属性。这些样式名基本上是遵循了web上的CSS的命名,只是按照JS的语法要求使用了驼峰命名法。
style属性可以是一个普通的JavaScript对象。还可以传入一个数组 —- 在数组中位置居后的样式对象比居前的优先级更高,这样可以间接实现样式的继承。
实际开发中组件的样式会越来越复杂,建议使用StyleSheet.create来集中定义组件的样式。
const styles = StyleSheet.create({
bigblue: {
color: 'blue',
fontWeight: 'bold',
fontSize: 30,
},
red: {
color: 'red',
},
});
常见的做法是按顺序声明和使用style属性,以借鉴CSS中的”层叠”做法(即后声明的属性会覆盖先声明的同名属性)。
组件尺寸
组件的高度和宽度决定了其在屏幕上显示的尺寸。
指定宽高
在样式中指定固定的width和height。React Native中的尺寸都是无单位的,表示的是与设备像素密度无关的逻辑像素点。
<View style={{width: 50, height: 50}} />
Android使用DP作为逻辑像素单位,iOS使用PT作为逻辑像素单位,逻辑像素与设备像素不一定相等。
弹性(Flex)宽高
在组件样式中使用flex可以使其在可利用的空间中动态地扩张或收缩。一般而言我们会使用flex:1来指定某个组件扩张以撑满所有剩余的空间。如果有多个并列的子组件使用了flex:1,则这些子组件会平分父容器中剩余的空间。如果这些并列的子组件的flex值不一样,则谁的值更大,谁占据剩余空间的比例就更大(即占据剩余空间的比等于并列组件间flex值的比)。
组件能够撑满剩余空间的前提是其父容器的尺寸不为零。如果父容器既没有固定的width和height,也没有设定flex,则父容器的尺寸为零。其子组件如果使用了flex,也是无法显示的。
<View style={{flex: 1}}>
<View style={{flex: 1, backgroundColor: 'powderblue'}} />
<View style={{flex: 2, backgroundColor: 'skyblue'}} />
<View style={{flex: 3, backgroundColor: 'steelblue'}} />
</View>
以上代码的运行结果为:三个View的宽度相同,而高度按比例占据父容器的剩余空间(flexDirection的默认值是column)。
Flexbox布局
React Native中的Flexbox的工作原理和web上的CSS基本一致,当然也存在少许差异。首先是默认值不同:flexDirection的默认值是column而不是row,而flex也只能指定一个数字值。
- flexDirection
- 表示布局的主轴方向,默认值为column
- column竖直轴方向,从上至下排列
- column-reverse竖直轴方向,从下至上排列
- row水平轴方向,从左至右排列
- row-reverse水平轴方向,从右至左排列
- justifyContent
- 表示子项的在主轴上的对齐方式,默认值为flex-start
- flex-start主轴的起点对齐
- flex-end主轴的终点对齐
- center主轴的中点对齐
- space-between两端对齐,子项之间的间隔都相等
- space-around子项两侧的间隔相等,因此子项之间的间隔等于子项与边框的间隔的2倍
- alignItems
- 表示子项的在次轴(与主轴垂直的轴)上的对齐方式,默认值为stretch
- flex-start次轴的起点对齐
- flex-end次轴的终点对齐
- center次轴的中点对齐
- baseline项目的第一行文字的基线对齐
- stretch如果子项在次轴方向上未设置固定的尺寸或设为auto,将占满整个容器在次轴的尺寸
组件
AppRegistry
AppRegistry模块是用来告知React Native哪一个组件被注册为整个应用的根容器。一般在整个应用里AppRegistry.registerComponent这个方法只会调用一次,注册应用(registerComponent)后才能正确渲染。
AppRegistry.registerComponent(appKey: string, getComponentFunc: ComponentProvider)
注意,registerComponent的第一个参数是一个字符串,必须和react-native init命令创建的项目名一致,第二个参数是一个函数,该函数返回应用的根组件。
Image
- 静态图片资源
source={require('./src/img/img.png')}
View
View 常用作其他组件的容器,来帮助控制布局和样式。
TextInput
处理用户输入的组件。onChangeText属性接受一个函数,该函数在文本变化时调用。onSubmitEditing属性接受一个函数,该函数在文本提交后(用户按下软键盘上的提交键)调用。
ScrollView
可以容纳多个不同或相同类型组件和视图的可滚动容器,默认为垂直滚动,将horizontal属性设为true可改成水平滚动。ScrollView适合用来显示数量不多的滚动元素。放置在ScollView中的所有组件都会被渲染,哪怕有些组件因为内容太长被挤出了屏幕外。
ListView
ListView组件用于显示一个垂直的滚动列表,其中的元素之间结构近似而仅数据不同。ListView更适于长列表数据,且元素个数可以增删。和ScrollView不同的是,ListView并不立即渲染所有元素,而是优先渲染屏幕上可见的元素。
ListView组件必须的两个属性是dataSource和renderRow。dataSource是列表的数据源,可以通过创建一个设置了rowHasChanged函数属性的ListView.DataSource的实例,然后给它传递一个普通的数据数组,作为数据源。而renderRow是一个函数,负责逐个解析数据源中的数据,然后返回一个设定好格式的组件来渲染。
class ListViewBasics extends Component {
// 初始化模拟数据
constructor(props) {
super(props);
const ds = new ListView.DataSource({
rowHasChanged: (r1, r2) => r1 !== r2
});
this.state = {
dataSource: ds.cloneWithRows([
'John',
'Joel',
'James',
'Jimmy',
'Jackson',
'Jillian',
'Julie',
'Devin'
])
};
}
render() {
return (
<View style={{
flex: 1,
paddingTop: 22
}}>
<ListView dataSource={this.state.dataSource} renderRow={(rowData) => <Text>{rowData}</Text>}/>
<FlatList data={[
{
key: 'Devin'
}, {
key: 'Jackson'
}, {
key: 'James'
}, {
key: 'Joel'
}, {
key: 'John'
}, {
key: 'Jillian'
}, {
key: 'Jimmy'
}, {
key: 'Judlie'
}, {
key: 'Jodel'
}, {
key: 'Jdohn'
}, {
key: 'ds'
}, {
key: 'daffafd'
}, {
key: 'Julsie'
}, {
key: 'Jimm3y'
}, {
key: 'Juddflie'
}, {
key: 'Jodfadel'
}, {
key: 'Jdgfgohn'
}, {
key: 'dfgfgs'
}, {
key: 'dafffgfafd'
}, {
key: 'gfgfg'
}, {
key: 'Julssdfsdfie'
}, {
key: 'Jimsdfsdfm3y'
}, {
key: 'Judsdfdfdflie'
}, {
key: 'dfdddsfsdf'
}, {
key: 'sdfdfddd'
}, {
key: 'dfgdddfgs'
}, {
key: 'dafdffgfafd'
}, {
key: 'gfgddfg'
}
]} renderItem={({item}) => <Text style={styles.item}>{item.key}</Text>}/>
</View>
);
}
}
FlatList
FlatList组件是一种垂直滚动的列表,该组件必须的两个属性是data和renderItem。data是列表的数据源,而renderItem接受一个函数,从数据源中逐个解析数据,然后返回一个设定好格式的组件来渲染。
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
SectionList是高性能的分组(section)列表组件,支持下面这些常用的功能:
- 完全跨平台。
- 支持水平布局模式。
- 行组件显示或隐藏时可配置回调事件。
- 支持单独的头部组件。
- 支持单独的尾部组件。
- 支持自定义行间分隔线。
- 支持下拉刷新。
- 支持上拉加载。
- 如果你的列表不需要分组(section),那么可以使用结构更简单的
。
网络
Fetch API
React Native提供了和web标准一致的Fetch API,用于满足开发者访问网络的需求。
fetch(url, config)
url参数表示资源地址,config参数可以用来定制HTTP请求一些参数,例如指定header参数,或是指定使用POST方法,又或是提交数据等等。
示例:
// 获取JSON数据
fetch('https://mywebsite.com/mydata.json')
// 提交JSON数据
fetch('https://mywebsite.com/endpoint/', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({firstParam: 'yourValue', secondParam: 'yourOtherValue'})
})
// 提交表单数据
fetch('https://mywebsite.com/endpoint/', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: 'key1=value1&key2=value2'
})
Fetch方法会返回一个Promise,这种模式可以简化异步风格的代码。
getMoviesFromApiAsync() {
return fetch('https://facebook.github.io/react-native/movies.json')
.then((response) => response.json()).then((responseJson) => {
return responseJson.movies;
}).catch((error) => {
console.error(error);
});
}
也可以在React Native应用中使用ES7标准中的async/await语法。
// 注意这个方法前面有async关键字
async getMoviesFromApi() {
try {
// 注意这里的await语句,其所在的函数必须有async关键字声明
let response = await fetch('https://facebook.github.io/react-native/movies.json');
let responseJson = await response.json();
return responseJson.movies;
} catch (error) {
console.error(error);
}
}
别忘了catch住fetch可能抛出的异常,否则出错时可能看不到任何提示。
默认情况下,iOS会阻止所有非https的请求。如果请求的接口是http协议,那么首先需要添加一个App Transport Security的例外。
AJAX
React Native中已经内置了XMLHttpRequest API(也就是俗称的ajax)。一些基于XMLHttpRequest封装的第三方库也可以使用,例如frisbee或是axios等。但注意不能使用jQuery,因为jQuery中还使用了很多浏览器中才有而RN中没有的东西(所以也不是所有web中的ajax库都可以直接使用)。
var request = new XMLHttpRequest();
request.onreadystatechange = (e) => {
if (request.readyState !== 4) {
return;
}
if (request.status === 200) {
console.log('success', request.responseText);
} else {
console.warn('error');
}
};
request.open('GET', 'https://mywebsite.com/endpoint/');
request.send();
需要注意的是,安全机制与网页环境有所不同:在应用中可以访问任何网站,没有跨域的限制。
WebSocket
React Native还支持WebSocket,这种协议可以在单个TCP连接上提供全双工的通信信道。
var ws = new WebSocket('ws://host.com/path');
// 打开一个连接
ws.onopen = () => {
ws.send('something'); // 发送一个消息
};
// 接收到了一个消息
ws.onmessage = (e) => {
console.log(e.data);
};
// 发生了一个错误
ws.onerror = (e) => {
console.log(e.message);
};
// 连接被关闭了
ws.onclose = (e) => {
console.log(e.code, e.reason);
};
参考文章