前面介绍了页面的概念,这里介绍下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提供的页面栈管理功能来实现后续的交互。