页面的生命周期

更新时间:2017/08/23 访问次数:6772

前面介绍了页面的概念,这里介绍下QAP应用(QAPApp)中 页面的生命周期,以及开发者可以利用这些生命周期事件做些什么。

1. 基础生命周期事件

一个页面最基本的生命周期包括以下四种:

事件 级别 描述
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.

以上就是页面的四种基础生命周期事件的触发场景,开发者可以在页面切换过程中做一些局部的刷新动作,以保持信息的一致性。

1.1 使用示例

这里利用Page.DidAppearPage.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触发时会保存新增的用户,供上一个列表页面实时刷新,效果如下图所示:

1.2 和组件生命周期的区别

和页面生命周期类似,前文提过组件也有一些类似的生命周期:

componentWillMount
componentDidMount
componentWillUnmount

但和页面生命周期不同的是,在页面第一次加载时才会触发上述相关方法,后续的页面push-pop过程中并不会触发到。

2. 前后台切换

以上是页面之间切换时的生命周期事件,如果是系统级别的前后台切换则会触发另外的事件:

QAP.on('Global.DidBecomeActive', ()=> {
            console.log('PageEventsDemo Global.DidBecomeActive.');
        });

        QAP.on('Global.DidEnterBackground', ()=> {
            console.log('PageEventsDemo Global.DidEnterBackground.');
        });

可以通过如上代码来监听前后台切换事件,开发者可以利用这些事件做一些数据存储动作,或者取消定时器等操作。
需要注意的是,当进入后台的事件触发后,只有一小段时间可以执行代码,所以不要在这里做过重的操作。

3. 生命周期事件代理

以上是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提供的页面栈管理功能来实现后续的交互。

FAQ

关于此文档暂时还没有FAQ
文档标签:
QAP
返回
顶部