![](https://img.haomeiwen.com/i1180547/15b23fd343bdfca0.png)
这里截取一个安卓模拟器的页面来说明。
实际要解决的问题
-
以
iOS
为例
不同于我们iOS
开发,假设我们现在用OC
来实现一个上图中的页面,通常要做的是在两个textField
输入框中获取用户的输入信息,而这两个textField
也是整个viewController
的property
属性变量。
我们在点击下方的注册按钮时,用正则去判断输入的合法性。
—— 一切都这么自然 -
RN
面临的问题
我们新建工程后,RN很自然的将整个页面作为一个总的父组件。然后根据页面中的布局,实际上是有三个子组件,分别是- 顶部的
码上公交
背景图 —— 姑且成为 Top组件 - 中间的输入区域 —— 分为电话号码输入; 验证码输入。 —— 称为A组件
- 底部的登录/注册按钮。 —— 称为B组件
中部的按钮中
TextInput
组件根据state
在B组件的内部获取用户的输入信息。那么就带来了一个问题,当我在C组件中按下登录时,C组件中并没有持有B组件中的输入框内容,要怎么办?
—— 解决方式,就是我们要说的组件间传值。 - 顶部的
解决方案 —— 组见间传值
先看下面两篇关于组件间传值的参考文章(筛选了比较久)
组件间传值参考文章一
组件间传值参考文章二
在熟悉props
和state
的基础上,继续下面的内容。
解决方案一
将child component B
中的输入内容,通过props
对应的回调函数,传给parent component
父组件。
通俗的理解,就是在父组件中,用一个state持有两个输入框的文本内容。而这两个状态机变量,和子组件中是类似的。而后在子组件中根据回调函数通知父组件修改。而后直接在组件C按下时,调用父组件内的合法性输入判断函数。
// 父组件中包含子组件时,将回调函数传给props
constructor(props){
super(props);
this.state = {
phoneNum:'',
veriCode:'',
}
}
changePhoneNum(num){
this.setState({phoneNum:num});
}
<ChildComponentB onEndInput={this.changePhoneNum.bind(this)} />
解决方案二
在组件B和组件C之间作平级的组件传值,这里就要引入JS
中的消息广播机制,DeviceEventEmitter
在B组件完成输入后,调用消息发送的广播。而后在C组件中增加两个监听,分别监听输入的电话号码
和输入的验证码
. 唯一需要担心和不大了解的是,JS中使用消息通信机制,是否和OC
中使用广播一样,虽然去耦,但是比较耗资源。
以下,是完整的代码,供参考
/**
* Created by Defore on 2017/8/16.
*/
import React, {Component} from 'react';
import {
StyleSheet,
Text,
View,
Dimensions,
TouchableOpacity,
TextInput,
Platform,
Image,
Button,
DeviceEventEmitter,
} from 'react-native';
import baseStyle from '../BaseStyles'
const {width, height} = Dimensions.get('window');
const loginBgIco = require('../srcImg/Login/login_bg.png');//750*350
const phoneIco = require('../srcImg/Login/num_default.png');//28*44
const phoneSelIco = require('../srcImg/Login/num_selected.png');//48*44
const veriCodeIco = require('../srcImg/Login/code_default.png');//44*44
const veriCodeSelIco = require('../srcImg/Login/code_selected.png');//44*44
const busBgIco = require('../srcImg/首页/index_bg.png');//466*246
export default class Login extends Component {
constructor(props) {
super(props);
this.state = {
phoneNum: '',
veriCode: '',
};
}
static navigationOptions = {
header: null,
};
render() {
return (
<View style={styles.container}>
<Image style={{width: width, height: 169 / 667 * height,}} source={loginBgIco}/>
<PhoneNoInput />
<View style={{width: width - 42, height: 1, backgroundColor: '#E6E6E6',}}/>
<VeriCodeInput />
<LoginBtnArea />
</View>
);
}
}
/* 登录 - 输入手机号 */
class PhoneNoInput extends Component {
constructor(props) {
super(props);
this.state = {
phoneImg: phoneIco,
phoneNumber: '',
};
}
// 若输入为空,就恢复成默认
checkWhetherEmptyInput() {
if (this.state.phoneNumber.length === 0) {
this.setState({phoneImg: phoneIco});
} else {
DeviceEventEmitter.emit('phone', this.state.phoneNumber);
}
}
render() {
return (
<View style={styles.inputView}>
<View style={styles.icoContainterView}>
<Image style={{width: 13.5, height: 22}} source={this.state.phoneImg}/>
</View>
<TextInput style={[baseStyle.regularFont, styles.phoneNoInput]} underlineColorAndroid={'transparent'}
placeholder={'请输入手机号'} placeholderTextColor={'#D5D5D5'}
keyboardType={Platform.OS === 'ios' ? 'number-pad' : 'numeric'}
returnKeyType={'done'}
onFocus={() => {
this.setState({phoneImg: phoneSelIco})
}}
onEndEditing={() => {
this.checkWhetherEmptyInput();
}}
onChangeText={(input) => {
this.setState({phoneNumber: input});
// DeviceEventEmitter.emit('phone', input);
}}
/>
</View>
)
}
}
/* 登录 - 输入验证码 */
class VeriCodeInput extends Component {
constructor(props) {
super(props);
this.state = {
veriCodeImg: veriCodeIco,
veriCode: '',
};
}
// 若输入为空,就恢复成默认
checkWhetherEmptyInput() {
if (this.state.veriCode.length === 0) {
this.setState({veriCodeImg: veriCodeIco});
} else
DeviceEventEmitter.emit('vericode', this.state.veriCode);
}
render() {
return (
<View style={styles.inputView}>
<View style={styles.icoContainterView}>
<Image style={{width: 22, height: 22}} source={this.state.veriCodeImg}/>
</View>
<TextInput style={[baseStyle.regularFont, styles.veriCodeInput]} underlineColorAndroid={'transparent'}
placeholder={'请输入验证码'} placeholderTextColor={'#D5D5D5'}
keyboardType={Platform.OS === 'ios' ? 'number-pad' : 'numeric'}
returnKeyType={'done'}
onFocus={() => {
this.setState({veriCodeImg: veriCodeSelIco})
}}
onEndEditing={() => {
this.checkWhetherEmptyInput()
}}
onChangeText={(input) => {
this.setState({veriCode: input});
// DeviceEventEmitter.emit('vericode', input);
}}
/>
<View style={{width: 1, height: 34 / 667 * height, backgroundColor: '#D9D9D9',}}/>
</View>
)
}
}
/*----------------- 登录按键 -----------------*/
class LoginBtnArea extends Component {
constructor(props) {
super(props);
this.state = {
phoneNum: '',
veriCode: '',
};
}
componentDidMount() {
//添加收听者,监听 电话号码/验证码时
this.phoneInputListen = DeviceEventEmitter.addListener('phone', (phoneNum) => {
console.log('收听到电话--?');
this.setState({phoneNum: phoneNum})
});
this.veriInputListen = DeviceEventEmitter.addListener('vericode', (code) => {
console.log('收听到验证码==');
this.setState({veriCode: code})
});
}
componentWillUnmount() {
this.phoneInputListen.remove();
this.veriInputListen.remove();
}
judgeLegalInput() {
console.log('电话号码' + this.state.phoneNum + '\n');
console.log('验证码' + this.state.veriCode + '\n');
}
render() {
return (
<TouchableOpacity style={styles.loginBtnArea} onPress={this.judgeLegalInput.bind(this)}>
<Text style={[baseStyle.regularFont, {fontSize: 16, color: 'white'}]}>注册/登录</Text>
</TouchableOpacity>
)
}
}
//---------------------------------------------
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'flex-start', alignItems: 'center',
backgroundColor: '#ffffff',
},
/* --------- 手机号输入 ---------*/
icoContainterView: {
width: 63, height: 61,
justifyContent: 'center', alignItems: 'center',
},
inputView: {
flexDirection: 'row',//从左往右
justifyContent: 'flex-start', alignItems: 'center',
height: 61, width: width,
},
phoneNoInput: {
fontSize: 16, color: '#76ABF1',
width: width - 63 - 20, height: 61,
},
/* --------- 验证码输入 ---------*/
veriCodeInput: {
fontSize: 16, color: '#76ABF1',
width: 182 / 375 * width, height: 61,//backgroundColor:'red',
},
/* --------- 登录按键 ---------*/
loginBtnArea: {
justifyContent: 'center', alignItems: 'center', marginTop: 155 /667* height ,
width: width - 40, height: 50, backgroundColor: '#A8CE47',
}
});
网友评论