前面介绍了页面的概念,这里介绍下QAP应用(QAPApp
)中 页面的生命周期,以及开发者可以利用这些生命周期事件做些什么。
一个页面最基本的生命周期包括以下四种:
事件 | 级别 | 描述 |
---|---|---|
WillAppear | 页面级别 | 当前页面即将进栈时触发 |
DidAppear | 页面级别 | 当前页面已经进栈时触发 |
WillDisappear | 页面级别 | 当前页面即将出栈或者下一个页面即将进栈时触发 |
DidDisappear | 页面级别 | 当前页面已经出栈或者下一个页面已经进栈时触发 |
以下是监听上述四个生命周期事件的代码:
import {createElement, Component, render} from 'rax'; import {Link, View, Text, TouchableHighlight, Button, Navigator} from 'nuke'; import QAP from 'QAP-SDK'; class PageEventsDemo extends Component { constructor(props) { super(props); QAP.on('Page.WillAppear', ()=> { console.log('PageEventsDemo Page.WillAppear.'); }); QAP.on('Page.DidAppear', ()=> { console.log('PageEventsDemo Page.DidAppear.'); }); QAP.on('Page.WillDisappear', ()=> { console.log('PageEventsDemo Page.WillDisappear.'); }); QAP.on('Page.DidDisappear', ()=> { console.log('PageEventsDemo Page.DidDisappear.'); }); } render() { return ( <View> <Button onPress={()=> { QAP.navigator.push({url: './image.js'}); }}>push</Button> <Button onPress={()=> { QAP.navigator.pop(); }}>pop</Button> </View> ); } } module.exports = PageEventsDemo; render(<PageEventsDemo/>);
当打开该页面时,会先后输出两行日志:
PageEventsDemo Page.WillAppear. PageEventsDemo Page.DidAppear.
点击push按钮打开下一个页面会输出:
PageEventsDemo Page.WillDisappear. PageEventsDemo Page.DidDisappear.
再由下一个页面pop返回到该页面时,会先后输出两行日志:
PageEventsDemo Page.WillAppear. PageEventsDemo Page.DidAppear.
最后由当前页面点击返回、pop出栈,会输出:
PageEventsDemo Page.WillDisappear. PageEventsDemo Page.DidDisappear.
以上就是页面的四种基础生命周期事件的触发场景,开发者可以在页面切换过程中做一些局部的刷新动作,以保持信息的一致性。
这里利用Page.DidAppear
和Page.WillDisappear
两个页面生命周期事件实现页面切换时的数据同步和刷新。
首先,我们创建一个空的列表页面,并在Page.DidAppear
事件触发时捞取用户列表进行展示:
'use strict'; import {createElement, Component, render} from 'rax'; import {View, Text, Modal, Slider, ListView, TouchableHighlight, Image, Button} from 'nuke'; import QN from 'QAP-SDK'; class DemoList extends Component { constructor(props) { super(props); this.state = { 'list':[], }; this.addNavButton(); QN.on('Page.DidAppear', ()=> { QN.sessionstore.get({ query: { key: 'userList' } }).then(result => { if (result.data.userList) this.setState({'list':result.data.userList}); }, error => { console.log('QN.sessionstore.get userList : ', error); }); }); } addNavButton = () => { QN.navigator.addButton({ query: { iconName: 'add', text: '添加', tapEvent: 'Page.addUser', // 或 `share` } }).then(result => { console.log(result); }, error => { console.log(error); }); QN.on('Page.addUser', ()=> { QN.navigator.push({url:'./addUser.js', title:'添加用户'}); }); } render() { return ( <ListView style={styles.listContainer} dataSource={this.state.list} renderRow={this.cellForRow}> </ListView> ); } cellForRow = (item, index) => { return <TouchableHighlight style={styles.listCell} onPress={() => {this.didSelectCell(item, index)}}> <View style={styles.listCellLeftView}> <Image style={styles.listCellImage} source={{uri:item.avatar}} /> <Text style={styles.listCellText}>{item.name},{item.gender},{item.age}岁</Text> </View> <Button style={styles.listCellButton}>编辑</Button> </TouchableHighlight>; } didSelectCell = (item, index) => { QN.navigator.push({url:item.url, title:item.name}); } } const styles = { listContainer: { flex: 1, backgroundColor: '#E1EFF8', }, listCell: { flex: 1, flexDirection: 'row', justifyContent: 'space-between', 'backgroundColor': '#E1EFF8', 'backgroundColor:active': '#cccccc', height: '110rem', borderBottomStyle: 'solid', borderBottomColor: '#dcdde3', borderBottomWidth: '1rem', }, listCellLeftView: { flex: 1, flexDirection: 'row', }, listCellImage: { marginLeft: '20rem', marginTop: '20rem', width: '80rem', height: '80rem', }, listCellText: { marginLeft: '40rem', marginTop: '40rem', }, listCellButton: { marginRight: '20rem', }, }; render(<DemoList />); export default DemoList;
在上述代码中,我们在导航栏添加了一个按钮,点击跳转到新增用户页面:
'use strict'; import {createElement, Component, render} from 'rax'; import {View, Text, Button, TextInput, ScrollView, Modal, Image, Switch} from 'nuke'; import QN from 'QAP-SDK'; class AddUserDemo extends Component { constructor(props) { super(props); this.state = { 'name': '', 'age': '', 'gender':'男', 'avatar': 'http://is1.mzstatic.com/image/thumb/Purple128/v4/33/5a/d1/335ad132-aba9-1c34-ca95-83d3f7c42d04/source/175x175bb.jpg', }; QN.on('Page.WillDisappear', ()=> { this.onPageWillDisappear(); }); } render() { return ( <ScrollView style={styles.container}> <View style={styles.hContainer}> <Text>姓名:</Text> <TextInput style={styles.nameInput} onInput={this.onNameInput}></TextInput> </View> <View style={styles.hContainer}> <Text>性别: </Text> <Switch defaultChecked={false} onValueChange={(value) => this.onSwitchChange(value)}/> <Text> {this.state.gender}</Text> </View> <View style={styles.hContainer}> <Text>年龄:</Text> <TextInput style={styles.ageInput} maxLength="3" value="20" onInput={this.onAgeInput}></TextInput> </View> </ScrollView> ); } onSwitchChange(value) { if (value) { this.setState({'gender':'女'}); this.setState({'avatar':'https://lh3.ggpht.com/ZnMt-3LCs0BgjF27il9SZn8eZFJshGi6ktCcEukUkwXsmq-COWg6chUBd3YG7o10MZUh=w300'}); } else { this.setState({'gender':'男'}); this.setState({'avatar':'http://is1.mzstatic.com/image/thumb/Purple128/v4/33/5a/d1/335ad132-aba9-1c34-ca95-83d3f7c42d04/source/175x175bb.jpg'}); } } onNameInput = (t) => { console.log('onNameInput : ', t.value); this.setState({'name':t.value}); } onAgeInput = (t) => { console.log('onAgeInput : ', t.value); this.setState({'age':t.value}); } onPageWillDisappear = () => { QN.sessionstore.get({ query: { key: 'userList' } }).then(result => { var userInfo = { 'name':this.state.name, 'age':this.state.age, 'gender':this.state.gender, 'avatar':this.state.avatar, }; var userList; if (result.data.userList) { userList = result.data.userList; } else { userList = []; } userList.push(userInfo); QN.sessionstore.set({ query: { userList: userList } }).then(result => { console.log('QN.sessionstore.set userList : ', result); }, error => { console.log('QN.sessionstore.set userList : ', error); }); }, error => { console.log('QN.sessionstore.get userList : ', error); }); } } const styles = { container: { flex: 1, backgroundColor: '#F5FCFF', paddingTop: '20rem', }, hContainer: { flexDirection: 'row', alignItems: 'center', paddingLeft: '20rem', }, nameInput: { borderStyle: 'solid', borderColor: '#dcdde3', borderWidth: '1rem', width: '300rem', height: '80rem', 'margin':'40rem' }, ageInput: { borderStyle: 'solid', borderColor: '#dcdde3', borderWidth: '1rem', width: '100rem', height: '80rem', 'margin':'40rem' }, }; render(<AddUserDemo />); export default AddUserDemo;
当从新增用户页面返回到上一个页面时,在Page.WillDisappear
触发时会保存新增的用户,供上一个列表页面实时刷新,效果如下图所示:
和页面生命周期类似,前文提过组件也有一些类似的生命周期:
componentWillMount componentDidMount componentWillUnmount
但和页面生命周期不同的是,在页面第一次加载时才会触发上述相关方法,后续的页面push-pop过程中并不会触发到。
以上是页面之间切换时的生命周期事件,如果是系统级别的前后台切换则会触发另外的事件:
QAP.on('Global.DidBecomeActive', ()=> { console.log('PageEventsDemo Global.DidBecomeActive.'); }); QAP.on('Global.DidEnterBackground', ()=> { console.log('PageEventsDemo Global.DidEnterBackground.'); });
可以通过如上代码来监听前后台切换事件,开发者可以利用这些事件做一些数据存储动作,或者取消定时器等操作。
需要注意的是,当进入后台的事件触发后,只有一小段时间可以执行代码,所以不要在这里做过重的操作。
以上是QAP提供给开发者对相关生命周期事件的感知机制,如果开发者想要代理这些事件,可以利用QAP提供的事件代理机制,包括页面的返回、关闭和刷新。
QAP.on('Page.back', ()=> { console.log('on PageEventsDemo Page.back.'); }); QAP.on('Page.close', ()=> { console.log('on PageEventsDemo Page.close.'); }); QAP.on('Page.reload', ()=> { console.log('on PageEventsDemo Page.reload.'); });
开发者可以通过以上代码监听代理返回、关闭和刷新事件,当用户触发相应操作时会输出如下日志:
on PageEventsDemo Page.back. on PageEventsDemo Page.close. on PageEventsDemo Page.reload.
这些事件代理功能可以让开发者做一些体验上的优化,比如在重要操作界面避免用户误操作返回、导致数据丢失。
需要注意的是,当开发者代理了以上事件后,也需要给出合理的后续交互流程,否则开发者的应用在交互评审时很可能会无法通过,导致无法正式发布该应用。
这种场景下,开发者可以利用QAP提供的页面栈管理功能来实现后续的交互。