ReactNative开发——自定义组件
定义组件
我自定义了一个对话框,这个对话框的样子如图所示:
直接上代码:
/** * 直接导出组件,不用写module.exports=ConfirmDialog */
export default class ConfirmDialog extends Component {
render() {
return (
<View style={styles.confirmCont}>
<View style={styles.dialogStyle}>
<Text style={styles.textPrompt}>
{/*提示语*/}
{this.props.promptToUser}
</Text>
<Text style={styles.yesButton}
numberOfLines={3} //控制3行,内容第一行显示回车,目的是让文本居中
onPress={this.props.userConfirmed}
>
{'\r\n'} 确 定
</Text>
<Text style={styles.cancelButton}
numberOfLines={3}
onPress={this.props.userCanceled}
>
{'\r\n'}取 消
</Text>
</View>
</View>
);
}
}
/** * 样式 */
let styles = StyleSheet.create({
confirmCont: {
position: 'absolute',top: 0,width: totalWidth,height: totalHeight,backgroundColor: 'rgba(52,52,0.5)',},dialogStyle: {
position: 'absolute',top: totalHeight * 0.2,left: totalWidth / 10,width: totalWidth * 0.8,height: totalWidth * 0.5,backgroundColor: 'white'
},textPrompt: {
position: 'absolute',top: 10,left: 10,fontSize: 20,color: 'black',yesButton: {
position: 'absolute',bottom: 10,width: totalWidth * 0.35,height: totalHeight * 0.13,backgroundColor: 'grey',color: 'white',textAlign: 'center'
},cancelButton: {
position: 'absolute',right: 10,textAlign: 'center',}
});
接收的参数
这个控件接收3个参数:
1. promptToUser : 父控件传过来的文本信息。
2. userConfirmed: 父控件传过来的函数,供我们确认按钮回调。
3. userCancel: 父控件传过来的函数,供我们取消按钮回调。
父控件传参
renderWithDialog() {
return (
<View style={styles.container}>
<TextInput style={styles.numberInputStyle}
placeholder={'请输入手机号'}
onChangeText={(newText) => this.updateNum(newText)}
/>
<Text style={styles.textPromptStyle}>
您输入的手机号码:{this.state.inputedNum}
</Text>
<TextInput style={styles.passwordInputStyle}
placeholder={'请输入密码'}
secureTextEntry={true}
onChangeText={(newText) => this.updatePw(newText)}
/>
<Text style={styles.bigTextPrompt}
onPress={() => this.userConfirmed()}
>
确 定
</Text>
{/*传入参数*/}
<ConfirmDialog
userConfirmed={this.userConfirmed.bind(this)}
userCanceled={this.userCanceled.bind(this)}
promptToUser={'使用' + this.state.inputedNum + '号码登录?'}
/>
</View>
);
其中传入参数代码为:
userConfirmed={this.userConfirmed.bind(this)}
userCanceled={this.userCanceled.bind(this)}
promptToUser={'使用' + this.state.inputedNum + '号码登录?'}
其中 this.userConfirmed
和 this.userCanceled
是父控件的函数。我的父控件这2个函数设置了setState()
来更新界面 bind(this)
是为了让子控件调用父控件函数的时候this 指向的是父控件。
下面是我父控件的部分定义:
export default class Register extends Component {
state = {
needToConfirm: false,}
userPressConfirm() {
this.setState((state) => { return {needToConfirm: true} }); } userConfirmed() { // 子控件确认按钮点击之后,会回调这里,因为我传参的时候使用了 ‘bind(this)' 所以这里的this还是父控件 this.setState((state) => { return {needToConfirm: false}; }); } userCanceled() { //子控件取消按钮的回调 this.setState((state) => { return {needToConfirm: false}; }); } updateNum(newText) { this.setState((state) => { return { inputedNum: newText,} });//{inputedNum} } updatePw(newText) { this.setState(() => { return { inputedPW: newText } }); } renderWithDialog() { return ( <View style={styles.container}> <TextInput style={styles.numberInputStyle} placeholder={'请输入手机号'} onChangeText={(newText) => this.updateNum(newText)} /> <Text style={styles.textPromptStyle}> 您输入的手机号码:{this.state.inputedNum} </Text> <TextInput style={styles.passwordInputStyle} placeholder={'请输入密码'} secureTextEntry={true} onChangeText={(newText) => this.updatePw(newText)} /> <Text style={styles.bigTextPrompt} onPress={() => this.userConfirmed()} > 确 定 </Text> {/*传入参数*/} <ConfirmDialog userConfirmed={this.userConfirmed.bind(this)} userCanceled={this.userCanceled.bind(this)} promptToUser={'使用' + this.state.inputedNum + '号码登录?'} /> </View> ); } render() { /*判断如果需要出现对话框,就显示带有对话框的页面*/ if (this.state.needToConfirm) return this.renderWithDialog(); /*一下是没有对话框的页面*/ return ( <View style={styles.container}> <TextInput style={styles.numberInputStyle} placeholder={'请输入手机号'} onChangeText={(newText) => this.updateNum(newText)} /> <Text style={styles.textPromptStyle}> 您输入的手机号码:{this.state.inputedNum} </Text> <TextInput style={styles.passwordInputStyle} placeholder={'请输入密码'} secureTextEntry={true} onChangeText={(newText) => this.updatePw(newText)} /> <Text style={styles.bigTextPrompt} onPress={() => this.userPressConfirm()} > 确 定 </Text> </View> ); } }
属性确认
当我们的组件供给其他同事使用的时候,其他同时可能不会去看我们的代码,以至于如果他们没有给我们的自定义控件传入应有的参数,我们的控件就会有问题。
所有我们就要声明自己组件所要的属性。
下面是我添加我们自定义控件声明属性的部分代码:
/** * 属性声明 * @type {{userConfirmed: (*),userCanceled: (*)}} */
ConfirmDialog.propTypes = {
userConfirmed: React.PropTypes.func.isrequired,userCanceled: React.PropTypes.func.isrequired,}
同时我们还可以给属性设置默认值:
/** * 默认属性 * @type {{promptToUser: string}} */
ConfirmDialog.defaultProps = {
promptToUser: '确定吗?'
}
这样同事如果在调试阶段没有父控件没有输入自定义控件必须要有的参数就会有异常告知:
属性确认的语法:
要求属性是指定的JavaScript基本类型
- 属性名称:React.PropTypes.array,
- 属性名称: React.PropTypes.bool,
- 属性名称: React.PropTypes.func,
- 属性名称: React.PropTypes.number,
- 属性名称: React.PropTypes.object,
- 属性名称: React.PropTypes.string,
要求属性是可渲染节点
可渲染节点指数字,字符串,数字数组,字符串数组。
* 属性名称: React.PropTypes.node
要求属性是某个指定类的实例
要求属性取值为特定的几个值
属性可以为指定类型中的任意一个
- 属性名称: React.PropTypes.oneOfType([React.PropTypes.string,React.PropTypes.number,React.PropTypes.instanceOf(NameOfAclass)]),
要求属性为指定类型的数组
要求属性是一个指定构成方式的对象
属性可以是任意类型
最后附上完整代码
这个代码实现的功能是,显示一个注册界面,
1. 用户点击确认之后,弹出对话框。
2. 用户点击确认按钮,跳转到一个页面,用户点击取消关闭对话框。
3. 我用的React Native 是 0.44 版,不说了,看代码。
index.andoid.js:
/** * Sample React Native App * https://github.com/facebook/react-native * @flow */
'user react'
import React from 'react';
import {AppRegistry} from 'react-native';
import {StackNavigator} from 'react-navigation'
/*注册页面*/
var RegisterLeaf = require('./RegisterLeaf');
/*等待页面*/
import WaitingLeaf from './WaitingLeaf';
// var WaitingLeaf = require('./WaitingLeaf');
const Project02 = StackNavigator({
Register: {screen: RegisterLeaf},Waiting: {screen: WaitingLeaf},});
AppRegistry.registerComponent('Project02',() => Project02);
RegisterLeaf.android.js
/** * Sample React Native App * https://github.com/facebook/react-native * @flow */
"use strict"
import React,{Component} from 'react';
import {
StyleSheet,Text,TextInput,View,BackHandler,} from 'react-native';
import ConfirmDialog from './ConfirmDialog';
let Dimensions = require('Dimensions');
let PixelRatio = require('PixelRatio');
let totalWidth = Dimensions.get('window').width;
let totalHeight = Dimensions.get('window').height;
let pixelRatio = PixelRatio.get();
let leftStartPoint = totalWidth * 0.1;
let componentWidth = totalWidth * 0.8;
export default class Register extends Component {
static navigationOptions = {
title: '注册页面'
}
state = {
inputedNum: '',inputedPW: '',needToConfirm: false,}
userPressConfirm() {
this.setState((state) => {
return {needToConfirm: true}
});
}
userConfirmed() {
this.setState((state) => {
return {needToConfirm: false};
});
//@R_761_404@面
this.props.navigation.navigate('Waiting',{
phoneNumber: this.state.inputedNum,userPw: this.state.inputedPW,});
}
userCanceled() {
this.setState((state) => {
return {needToConfirm: false};
});
}
componentDidMount() {
console.log("Register Did Mount.");
}
componentWillUnmount() {
console.log("Register Will Unmount.");
// BackHandler.removeEventListener("hardwareBackPress")
}
componentWillUpdate() {
console.log("Register will Upldate");
}
componentWillMount() {
console.log("Register Will Mount");
// BackHandler.addEventListener("hardwareBackPress",function () {
// console.log("PressHardwareBack")
// return true;
// })
}
componentDidUpdate() {
console.log("Register Did Update");
};
updateNum(newText) {
this.setState((state) => {
return {
inputedNum: newText,}
});//{inputedNum}
}
updatePw(newText) {
this.setState(() => {
return {
inputedPW: newText
}
});
}
shouldComponentUpdate() {
// if (this.state.inputedNum.length < 3) return false;
return true;
}
renderWithDialog() {
return (
<View style={styles.container}> <TextInput style={styles.numberInputStyle} placeholder={'请输入手机号'} onChangeText={(newText) => this.updateNum(newText)} /> <Text style={styles.textPromptStyle}> 您输入的手机号码:{this.state.inputedNum} </Text> <TextInput style={styles.passwordInputStyle} placeholder={'请输入密码'} secureTextEntry={true} onChangeText={(newText) => this.updatePw(newText)} /> <Text style={styles.bigTextPrompt} onPress={() => this.userConfirmed()} > 确 定 </Text> {/*传入参数*/} <ConfirmDialog userConfirmed={this.userConfirmed.bind(this)} userCanceled={this.userCanceled.bind(this)} promptToUser={'使用' + this.state.inputedNum + '号码登录?'} /> </View> ); } render() { /*判断如果需要出现对话框,就显示带有对话框的页面*/ if (this.state.needToConfirm) return this.renderWithDialog(); /*一下是没有对话框的页面*/ return ( <View style={styles.container}> <TextInput style={styles.numberInputStyle} placeholder={'请输入手机号'} onChangeText={(newText) => this.updateNum(newText)} /> <Text style={styles.textPromptStyle}> 您输入的手机号码:{this.state.inputedNum} </Text> <TextInput style={styles.passwordInputStyle} placeholder={'请输入密码'} secureTextEntry={true} onChangeText={(newText) => this.updatePw(newText)} /> <Text style={styles.bigTextPrompt} onPress={() => this.userPressConfirm()} > 确 定 </Text> </View> ); } } const styles = StyleSheet.create({ numberInputStyle: { top: 20,left: leftStartPoint,width: componentWidth,backgroundColor: 'gray',fontSize: 20 },textPromptStyle: { top: 30,bigTextPrompt: { top: 70,color: 'white',textAlign: 'center',fontSize: 60 },passwordInputStyle: { top: 50,container: { flex: 1,backgroundColor: 'white' },}); module.exports = Register;
WaitingLeaf.android.js
/** * Created by Administrator on 5/25/2017. */
import React,{Component} from 'react';
import {View,StyleSheet,BackHandler} from 'react-native';
export default class WaitingLeaf extends Component {
static navigationOptions = {
title:'等待'
}
goBack() {
this.props.navigation.goBack();
}
componentDidMount() {
console.log("WaitingLeaf Did Mount.");
}
componentWillUnmount() {
console.log("WaitingLeaf Will Unmount.");
}
componentWillUpdate() {
console.log("WaitingLeaf will Update");
}
componentWillMount(){
console.log("WaitingLeaf Will Mount");
}
componentDidUpdate(){
console.log("WaitingLeaf Did Update");
};
render() {
const params = this.props.navigation.state.params;
// const {goBack} = this.props.navigation;
return (
<View style={styles.container}> <Text style={styles.textPromptStyle} > 注册使用手机号:{params.phoneNumber} </Text> <Text style={styles.textPromptStyle}> 注册使用的密码:{params.userPw} </Text> <Text style={styles.bigTextPrompt} onPress={() => this.goBack()} > 返回 </Text> </View> ) } } let styles = StyleSheet.create({ container: { flex: 1,justifyContent: 'center',alignItems: 'center',backgroundColor: '#F5FCFF' },textPromptStyle: { fontSize: 20,bigTextPrompt: { width: 300,}) module.exports = WaitingLeaf;
ConfirmDialog.js
/** * Created by Administrator on 5/25/2017. */
import React,{Component} from 'react';
import {StyleSheet,View} from 'react-native';
import Dimensions from 'Dimensions';
/** * 获得窗口的宽高,这里的宽高取决于父组件给自己分配的大小 */
let totalWidth = Dimensions.get('window').width;
let totalHeight = Dimensions.get('window').height;
/** * 直接导出组件,不用写module.exports=ConfirmDialog */
export default class ConfirmDialog extends Component {
render() {
return (
<View style={styles.confirmCont}> <View style={styles.dialogStyle}> <Text style={styles.textPrompt}> {/*提示语*/} {this.props.promptToUser} </Text> <Text style={styles.yesButton} numberOfLines={3} //控制3行,内容第一行显示回车,目的是让文本居中 onPress={this.props.userConfirmed} > {'\r\n'} 确 定 </Text> <Text style={styles.cancelButton} numberOfLines={3} onPress={this.props.userCanceled} > {'\r\n'}取 消 </Text> </View> </View> ); } } /** * 属性声明 * @type {{userConfirmed: (*),userCanceled: (*)}} */ ConfirmDialog.propTypes = { userConfirmed: React.PropTypes.func.isrequired,} /** * 默认属性 * @type {{promptToUser: string}} */ ConfirmDialog.defaultProps = { promptToUser: '确定吗?' } /** * 样式 */ let styles = StyleSheet.create({ confirmCont: { position: 'absolute',top: 0,backgroundColor: 'rgba(52,0.5)',dialogStyle: { position: 'absolute',top: totalHeight * 0.2,left: totalWidth / 10,width: totalWidth * 0.8,height: totalWidth * 0.5,textPrompt: { position: 'absolute',top: 10,left: 10,fontSize: 20,color: 'black',yesButton: { position: 'absolute',bottom: 10,width: totalWidth * 0.35,height: totalHeight * 0.13,backgroundColor: 'grey',textAlign: 'center' },cancelButton: { position: 'absolute',right: 10,} }); // module.exports = ConfirmDialog;