// 1、Modal组件的使用 // 2、TextInput组件的使用 // 3、用户登录界面的设计 // 3.1 定时器的使用 // 3.2 小技巧--根据不同的state显示不同的view // 3.3 子组件给父组件的回调函数 // 3.4 异步存储获取本地资源 // // // 一、 // 1、Modal组件:Modal组件可以用来覆盖包含React Native根视图的原生视图(如UIViewController,Activity)。 // 2、TextInput组件:TextInput是一个允许用户在应用中通过键盘输入文本的基本组件。本组件的属性提供了多种特性的配置,譬如自动完成、自动大小写、占位文字,以及多种不同的键盘类型(如纯数字键盘)等等。 <Modal animationType={} //可选属性有'none', 'slide', 'fade transparent={} //是否透明,设置是否为透明的,true或者是false visible={} //设置此modal是否为可见的true或者是false,一般由状态管理器来设置 onRequestClose={() => { } } //销毁modal界面时调用,一般就是设置visible的属性为false就行了 onShow={} //模态在显示的时候调用此函数 > {/*这里面就是覆盖在上面的内容*/} <View style={styles.modalContant}> <Icon name="ios-close-outline" style={styles.backfromModal} size={45} onPress={this._backfromModal} /> <View style={this.commentBox}> <View style={styles.commentNeirong}> <TextInput placeholder={'快来评论吧'} //如果没有任何文字输入,会显示此字符串,即提示信息 style={styles.pinlun} onFocus={this._focus} //当文本框获得焦点时调用此方法 onBlur={this._blur} //当文本框失去焦点时调用此方法 defaultValue={this.state.content} //默认值,即可编辑的一开始就在输入框中 onChangeText={(text)=>{ this.setState({ content:text }) //使用onChangeText写入state,然后从this.state中取出值。这是唯一的从输入框中取出输入值方法,text就是输入的内容 }} /> </View> </View> <Button onPress={this._submit} style={styles.submit} > 提交评论 </Button> </View> </Modal> // TextInput在安卓上默认有一个底边框,同时会有一些padding。如果要想使其看起来和iOS上尽量一致,则需要设置padding: 0,同时设置underlineColorAndroid="transparent"来去掉底边框。 // 二、用户登录界面 export default class Loginin extends Component { constructor(props) { super(props) this.state={ phoneNumber:'', //电话号码 codeAlreadysSend:false, //标记是否点击了获取验证码,即是否成功的发送了请求验证码的请求 verifyCode:'', //验证码 seconds:60 //倒计时 } } render() { return ( <View style={styles.container}> <View style = {styles.signupBox}> <Text style = {styles.textTitle}> 快速登录</Text> <View style={{height:45}}> <TextInput placeholder={'输入手机号'} autoCapitalize={'none'} //控制TextInput是否要自动将特定字符切换为大写 autoCorrect={false} //如果为false,会关闭拼写自动修正。默认值是true。 keyboardType={'phone-pad'} //决定弹出的何种软键盘的 style={styles.inputArea} underlineColorAndroid='transparent' // onChangeText={(text)=>{ this.setState({ phoneNumber:text }) }} /> </View> {this.state.codeAlreadysSend ? //判断是否已经成功发送了请求验证码的请求 <View style={styles.verifyCodeBox}> <TextInput placeholder={'输入验证码'} autoCapitalize={'none'} autoCorrect={false} keyboardType={'phone-pad'} style={styles.inputArea} underlineColorAndroid='transparent' onChangeText={(text)=>{ this.setState({ verifyCode:text }) }} /> {this.state.seconds === 0 ? //判断倒计时是否结束 <View style = {styles.countDown}> <Text style = {styles.countdownText} onPress={this._getVerifyCode}>重新获取</Text> {/*如果倒计时结束,那么重新获取验证码*/} </View> : <View style = {styles.countDown}> <Text style = {styles.countdownText}>剩余{this.state.seconds}秒</Text> </View> } </View> : null } {this.state.codeAlreadysSend ? //根据不同的状态显示不同的View,用三元运算符 <View style={styles.sendBtn}> <Text style={styles.btnText} onPress={this._login}>登录</Text> </View> : <View style={styles.sendBtn}> <Text style={styles.btnText} onPress={this._getVerifyCode}>获取验证码</Text> </View> } </View> </View> ); } //点击登录按钮 _login = ()=> { //去服务器验证手机号码与验证码是否匹配 //正则匹配 let phoneNumber = this.state.phoneNumber let verifyCode = this.state.verifyCode if(!phoneNumber || !verifyCode){ alert('手机号码或验证码不能为空') return //return后将不在执行下面的代码 } let body = { phoneNumber:phoneNumber, code:verifyCode }; let url = config.apis.base + config.apis.verify request.post(url,body) .then( (data)=>{ if(data && data.success){ this.props.afterLogin(data.data); //向父组件回调数据(login是要放在App.js中的,要放到tab的前面) }else{ alert('获取验证码失败,请检查您的手机号是否正确') } } ) .catch((err)=>{ alert('错误'+err) }) } //点击获取验证码 _getVerifyCode = ()=> { //去服务器获取验证码 //正则匹配 let phoneNumber = this.state.phoneNumber if(!phoneNumber){ alert('手机号码不能为空') return } let body = { phoneNumber:phoneNumber }; let url = config.apis.base + config.apis.signup request.post(url,body) .then( (data)=>{ if(data && data.success){ {this._showVerifyCode()} //请求成功显示输入验证码的输入框和倒计时(都是由状态机控制着) }else{ alert('获取验证码失败,请检查您的手机号是否正确') } } ) .catch((err)=>{ alert('错误'+err) }) } //显示验证码的输入框和倒计时 _showVerifyCode=()=>{ this.setState({ codeAlreadysSend:true, seconds:5 }) //开始倒计时,this._setInterval的目的是将setInterval绑定到this,每一秒钟状态机中的seconds要减去一 this._interval = setInterval(()=>{ if(this.state.seconds === 0){ clearInterval(this._interval) return } this.setState({ seconds:this.state.seconds - 1 })},1000); } /** * 生命周期方法,组件将被卸载之前 */ componentWillUnmount(){ this._interval && clearInterval(this._interval) //用计时器必须在组件将被卸载前清除计时操作,不然容易出问题 } } // react-native官网说:我们发现很多React Native应用发生致命错误(闪退)是与计时器有关。具体来说,是在某个组件被卸载(unmount)之后,计时器却仍然在运行。要解决这个问题,只需铭记在unmount组件时清除(clearTimeout/clearInterval)所有用到的定时器即可: export default class Hello extends Component { componentDidMount() { this.timer = setTimeout( () => { console.log('把一个定时器的引用挂在this上'); }, 500 ); } componentWillUnmount() { // 请注意Un"m"ount的m是小写 // 如果存在this.timer,则使用clearTimeout清空。 // 如果你使用多个timer,那么用多个变量,或者用个数组来保存引用,然后逐个clear this.timer && clearTimeout(this.timer); } }; // 在App.js中,已进入render函数,首先判断本地存储中是否有用户信息 if(!this.state.logined){ //这里每执行一次render函数都会重新判断一次logined。 return( <Login afterLogin={this._afterLogin}/> //用户登录页面,放在tab组件的外面 ) } // 用户第一次打开App的时候,登录成功后会将用户信息持久化到本地 //用户登录成功的回调函数(这里是子组件登陆成功,给父组件的回调) _afterLogin = (user) => { // user是一个用户信息对象 let user2 =JSON.stringify(user); AsyncStorage.setItem('user',user2) //异步存储用户信息到本地 .then( //then()函数是上一步成功后执行 ()=>{ this.setState({ logined:true, //注意:state每改变一次,就重新渲染一次(即重新执行一次render函数), user:user2 // 所以登陆成功后的页面跳转是不需要Navigator的。 }) } ) .catch((err)=>{ alert('存储发生错误'+err) }) //异步获取用户登录状态和信息 _asyncGetAppStatus = ()=> { AsyncStorage.getItem('user') .then( (data)=>{ let user; let newState = {}; //定义一个空对象 if(data){ user = JSON.parse(data); //JSON.parse()方法用来解析json字符串成JavaScript对象 } if(user && user.accesssToken){ newState.logined = true; newState.user = user; //就相当于 newState = {logined:true,user:user} }else{ newState.loaded = false; } this.setState(newState); } ) .catch((err) =>{ alert('AsyncStorage err'+err) }) } }
宝宝秀项目学习(四)
最新推荐文章于 2023-03-26 17:12:37 发布