微信小程序使用page-container实现滑动返回拦截与二次确认

3,975 阅读4分钟

最近开发小程序期间,有一个较大的表单页面,用户编辑期间若误触返回键或误触发滑动返回,再次进入页面表单数据会丢失,当然可以实现记住表单状态,但会增加代码复杂度,感觉不够优雅。遂去搜索小程序返回拦截的实现,大部分文章并没有很好的达到效果,找到了一个个人感觉还较好的实现,微信小程序 / UNIAPP --- 阻止小程序返回(顶部导航栏返回、左 / 右滑手势、安卓物理返回键和调用 navigateBack 接口) - 简书,但感觉还是不符合我的需求,我想要实现类似我们在退出一些app首页时会弹出一个toast那种效果,于是我参考以上代码做了如下实现,也是封装为了一个组件。

代码实现

<!--components/back-confirmation/back-confirmation.wxml-->
<page-container show="{{show}}" overlay="{{false}}" bind:leave="leave" message="{{message}}"> </page-container>

首先页面代码就是一个无显示无遮罩的page-container,这样我们把这个组件引入到页面中时对显示没有任何影响。新加了一个message属性用于自定义toast消息。

// components/back-confirmation/back-confirmation.js
let interval = null

Component({
    properties: {
        show: {
            type: Boolean,
            value: false
        },
        message: {
            type: String,
            value: '再按一次退出编辑'
        }
    },

    data: {},

    lifetimes: {
        detached() {
            if (interval) {
                clearInterval(interval)
            }
        }
    },

    observers: {
        'show': function (show) {
            if (!show) {
                if (interval) {
                    clearInterval(interval)
                }
            }
        }
    },

    methods: {
        async leave() {
            if (interval) {
                clearInterval(interval)
            }

            if (this.data.show) {
                await wx.showToast({
                    title: this.data.message,
                    icon: 'none',
                })
                interval = setInterval(() => {
                    this.setData({
                        show: true
                    })
                }, 2000)
            } else {
                await wx.navigateBack()
            }
        },
    }
})

对比参考文章,js代码的主要区别就是弹窗改为了toast,另外加了一个interval,如果用户只是误触,不进行二次确认则会在一定时长后重新恢复为需要二次确认。另外我对取消show加了一个observer,有什么作用在后面应用时再讲。

使用方法

<back-confirmation show="{{useBackConfirmation}}"/>

把useBackConfirmation的值设为true,一个退出页面的二次确认就实现了,使用效果如下,在第一下滑动返回时弹出toast消息,2秒内再次滑动才会退出页面,超过两秒则会恢复原状态,需要重新二次确认。

b0ac5e9339845980cc179b3db3ae2057.jpg

滑动返回是一个比较容易误触发的操作,但若我们的程序有顶部导航栏,顶部导航栏则相对很少误触,那我们希望若是点击导航栏就直接退出。但是我们在代码调用wx.navigateBack()时还是会被我们的二次确认拦截,这就需要先手动把组件的show值关闭,然后在调用wx.navigateBack(),也就是如下代码

async goBack() {
    this.setData({
        useBackConfirmation: false,
    })
    // 立即退出无效
    setTimeout(() => {
        wx.navigateBack()
    }, 10)
},

在返回按钮上绑定该方法,改变show值时前面提到的observer会把interval关掉,避免手动改变后马上又被恢复的情况出现,另外set值后等一定时间再调用wx.navigateBack(),不然可能会有bug。

需要注意不要在小程序首页使用该封装后的组件,不符合小程序开发规范,另外因为首页本身是无法调用wx.navigateBack()的,我也没有测试到底可不可用。

理解page-container的原理

page-container组件的所有属性,最重要的是show值。在页面上引入这个组件后,若show值为true,页面上所有各种方式触发的返回操作都会被这个组件所拦截,然后自动将值置为false。当值为false后,这个组件就没有作用了,但是我们可以重新赋值,就能让它重新恢复拦截。 在官方文档中,示例代码在page-container中是有具体组件的,这可能误导我们忽略了让它去实现返回二次确认这种无任何显示的最纯粹的功能。当然,基于page-container其实还能实现各种复杂的覆盖在页面之上的组件。

写在最后

以上是我在互联网发布的第一个技术分享,其实比较简单,但因为在网上没能找到比较好的方案,所以选择了发布出来。最近开发中其实还遇到了很多问题,本来还想自己建个博客的,但是实在是没有时间,就先写这一篇发布在掘金上了,希望能帮助到一些人。