在使用 RN 进行跨平台应用开发时,官方提供的组件往往是有限的,并且很多组件并不是多平台通用的,有些只针对特别的平台。此时,要想在应用开发上保持页面样式的一致性,除了直接选择第三方开源库以外,另一个有效的手段就是自定义组件。
本小节我们来自定义一个弹框组件。
首先我们简单复习一下 ES6 中导入导出模块的相关知识。
// 组件导出export default class App extends Component{ ...}
// 组件导入import App from './App'除了组件外,变量和常量也支持导入和导出。
// 变量和常量导出var name = '张三'const age = '18'export { name, age }
// 变量和常量的导入import { name, age } from './App'方法的导入以及导出,和变量、常量的导入导出类似。
// 方法导出export function sum(a, b) { return a + b}
// 方法导入import { sum } from './Util'另外,我们还会使用到 propTypes。通常,通用组件需要使用自定义属性的方式接收外界传入的值,如果是必须要传入的值,可以使用 isRequired 关键字。例如:
static propTypes = { title: PropTypes.string.PropTypes.func.isRequired, content: PropTypes.string,}需要注意的是,由于 propTypes 在 15.0.0 版本中已经被移除掉了,所以在 15.5.0 以及之后的版本中,需要使用新的方式引入。
import PropTypes from 'prop-types'好了,前置内容介绍完毕后,接下来我们就来封装第一个自定义组件——弹框组件。
上图是封装好之后的效果,可以看到,整个弹框由 4 个部分组成,分别是图片、标题、内容、确认按钮以及关闭按钮。其中图片、标题、内容、确认按钮内容都是应该在使用组件时传递进去的。
完整的封装组件代码如下:
import React, { Component } from 'react'import PropTypes from 'prop-types'import { View, Text, TouchableOpacity, Image, StyleSheet, ImageBackground, Dimensions,} from 'react-native'
const { width } = Dimensions.get('window')
export default class FreeDialog extends Component { static propTypes = { isShow: PropTypes.bool.isRequired, title: PropTypes.string, content: PropTypes.string, buttonContent: PropTypes.string, closeDialog: PropTypes.func.isRequired, imageSource: PropTypes.string.isRequired, }
closeDialogHandle() { this.props.closeDialog() }
render() { if (!this.props.isShow) { return null } else { return ( <View style={styles.containerBg}> <View style={[styles.dialogBg]}> <Image source={this.props.imageSource} style={styles.logoStyle} /> <Text style={styles.titleStyle}>{this.props.title}</Text> <Text style={styles.contentStyle}>{this.props.content}</Text> <TouchableOpacity> <ImageBackground resizeMode="stretch" source={require('../images/commen_btn.png')} style={styles.buttonStyle} > <Text style={styles.btnContentStyle}> {this.props.buttonContent} </Text> </ImageBackground> </TouchableOpacity> </View>
<TouchableOpacity style={styles.btnCloseStyle} onPress={this.closeDialogHandle.bind(this)} > <Image source={require('../images/ic_close.png')} style={{ height: 38, width: 38 }} /> </TouchableOpacity> </View> ) } }}
const styles = StyleSheet.create({ containerBg: { backgroundColor: 'rgba(0, 0, 0, 0.7)', position: 'absolute', left: 0, right: 0, bottom: 0, top: 0, overflow: 'hidden', justifyContent: 'center', alignItems: 'center', }, dialogBg: { width: width - 100, backgroundColor: '#ffffff', borderRadius: 10, overflow: 'hidden', alignItems: 'center', }, logoStyle: { height: ((width - 100) * 258) / 400, width: width - 100, }, titleStyle: { marginTop: 14, color: '#333333', fontSize: 18, fontWeight: '600', }, contentStyle: { marginTop: 5, color: '#333333', fontSize: 14, fontWeight: '400', }, buttonStyle: { height: ((width - 135) * 88) / 480, width: width - 180, marginTop: 36, marginBottom: 22, alignItems: 'center', justifyContent: 'center', }, btnContentStyle: { fontSize: 16, color: 'white', textAlign: 'center', fontWeight: '600', }, btnCloseStyle: { padding: 10, marginTop: 33, alignItems: 'center', },})在 App.js 根组件中使用测试:
import React, { PureComponent } from 'react'import { TouchableOpacity, StyleSheet, Text, View, Dimensions,} from 'react-native'import FreeDialog from './components/FreeDialog'
const { width } = Dimensions.get('window')
export default class DialogPage extends PureComponent { constructor(props) { super(props) this.state = { isShowDialog: false, } }
renderDialog() { return ( <FreeDialog isShow={this.state.isShowDialog} closeDialog={this.closeDialog.bind(this)} title={'年终大促'} content={'您有新的新年礼品,请查收!'} buttonContent={'新年礼品请查收'} imageSource={require('./images/dialog_bg.png')} /> ) }
showDialog() { this.setState({ isShowDialog: true, }) }
closeDialog() { this.setState({ isShowDialog: false, }) }
render() { return ( <View style={styles.container}> <TouchableOpacity style={styles.btnContainer} onPress={this.showDialog.bind(this)} > <Text style={styles.textStyle}>免费咨询医生</Text> </TouchableOpacity> {this.renderDialog()} </View> ) }}
const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor: '#F5FCFF', }, btnContainer: { marginTop: 15, marginLeft: 10, marginRight: 10, backgroundColor: '#EE7942', height: 38, width: width - 100, borderRadius: 5, justifyContent: 'center', alignItems: 'center', }, textStyle: { color: '#ffffff', fontSize: 18, },})