w***@gmail.com
w***@gmail.com
  • 发布:2023-05-12 14:23
  • 更新:2023-08-10 15:11
  • 阅读:1622

app中使用subNVue原生子窗体实现全局弹窗,所有页面皆可显示遮罩

分类:uni-app

!!!!产品需求描述:

1、所有接口请求时把当前版本号和这个接口是否检查更新参数等加上,后端拿到数据后与当前数据库存储的最新版本号是否一致,不一致则抛错并带有最新版本信息。
2、前端在拦截器中进入判断弹窗弹出流程,(h5页面使用全局组件注册即可,当时以为在App上也可以正常显示,哪知道不行),随即使用subNVue原生子窗体实现。过程中遇到一些问题如下。

!!!!开发过程中问题描述:

1、因在拦截器中做处理,会存在多个请求发出,所以需要定义一个弹窗是否已经显示过弹窗,第一个接口触发版本不对时,未弹起过,则唤起弹窗。反之后面的接口触发版本不对则不再弹起弹窗。
2、注意在index文件中无法获取到最新的vuex内容无法实时更新,所以改用uni.getStorageSync()和uni.setStorageSync(),获取最新的值或内容。
3、subNVue原生子窗体,在每次onLaunch时都会初始化,所以在里面使用vuex数据也是不可靠的。得使用uni.getStorageSync()和uni.setStorageSync(),获取最新的值或内容。
4、2,3条建议用来缓存实现一些不重要比较,变化不频繁的数据。
5、具体更新传递弹窗页面信息,使用页面通信,uni.$on(),uni.$emit()。来实现弹窗内容是最新版本信息。若使用uni.getStorageSync()和uni.setStorageSync(),会导致显示更新内容滞后,显示的其实是上一次的。

此文为实现需求的具体实现思路

1.新建原生子窗体目录文件

a.配置 nvue 文件路径,nvue 文件需放置到使用 subNvue 的页面文件目录下,

b.创建文件,文件路径:pages/subNVue/popup.nvue

2.subNVue 子窗体的 pages.json 配置,建议直接配置在首页路径下,其他配置注意事项查看官方文档

{    
    "pages": [{    
        "path": "pages/index/index", //首页    
        "style": {    
            "app-plus": {    
                "subNVues":[{    
                    "id": "concat", // 唯一标识    
                    "path": "pages/index/subnvue/concat", // 页面路径    
                    /*"type": "popup",  这里不需要*/    
                    "style": {    
                        "position": "absolute",    
                        "dock": "right",    
                        "width": "100rpx",    
                        "height": "150rpx",    
                        "background": "transparent"  //实测在为transparent时,tabbar页面唤起自带遮罩,  
                    }    
                }]    
            }    
        }    
    },  
//放在tabar路径后面  
// #ifdef APP-PLUS  
        {  
            "path": "pages/subnvue/popup",  
            "style": {  
                "navigationBarTitleText": "",  
                "disableScroll": true,  
                "bounce":"none",  
                "navigationStyle": "custom"  
            }  
        },  
// #endif  
    ]    
}

3.在App.vue页面配置,页面注册事件监听方法

onShow: function() {  
            console.log('App Show')  
            // 获取用户信息if  
            // #ifdef APP-PLUS || APP-NVUE  
            // app每次onshow先关闭之前注册的事件监听,然后重新注册  
            uni.$off('popup')  
            // 用于接收原生子窗体页面发出的页面通信事件,用于关闭全局弹窗  
            uni.$on('popup', (data) => {  
                if (!data.isShow) {  
                    const subNVue = uni.getSubNVueById('popup');  
                    subNVue.hide('popup', 300)  
                }  
            })  
            // #endif  
            // #ifdef APP-PLUS  
            hotUpdate.versionAutoUpdate(this.versionCode)//热更新方法  
            // #endif  
        },

4. 拦截器中接口校验到新版本抛错

if (res.statusCode == 412) {  
    // 用于判断是否已经弹过弹窗  
    const isShowPromptPopup = uni.getStorageSync('isShowPromptPopup')  
    // 为第一次检验到,且没有弹过窗走一下校验  
    if (!isShowPromptPopup) {  
        // #ifdef H5  
        setTimeout(() => {  
            promptPopup.open({  
                show: true  
            })  
        }, 1000)  
        // #endif  
        // #ifdef APP-PLUS || APP-NVUE  
        // 处理弹窗title,更新内容  
        let showInfo = {  
            title:'',  
            arr:[],  
            setBac:false  
        }  
        let descCn = res.data.error.desc.split(';')[0]  
        let descEn = res.data.error.desc.split(';')[1]  
        showInfo.title = res.data.error.title  
        if (uni.getStorageSync("lang") == 'ch') {  
            showInfo.arr = descCn.split(',')  
        } else {  
            showInfo.arr = descEn.split(',')  
        }  
        // 在 subNVue/vue 页面触发事件  
        if (store.state.whiteList.findIndex(item => item == route) != -1) {  
                             //因为路由白名单为固定内容,所以可以使用vuex数据,当前路由通过uni的api获取。  
            // 判断路由白名单是否显示遮罩,使用原生子窗体,挂载在tabbar页面的话只能在tabbar页面显示遮罩,这时需要手动控制其他页面额外手动设置遮罩  
            showInfo.setBac = false  
            uni.$emit('subPromptmsg', showInfo);  
        } else {  
            showInfo.setBac = true  
            uni.$emit('subPromptmsg', showInfo);  
        }  
        setTimeout(() => {  
            const subNVue = uni.getSubNVueById('popup');  
            subNVue.show('slide-in-center', 200, () => {})  
        }, 1000)  
        // #endif  
    }  
    uni.setStorageSync('isShowPromptPopup', true)  
    return  
}  

5.原生子窗体页面

<template>  
    <view style="flex-direction: column;align-items: center;justify-content: center;" @click.stop="" :style="setBac?'background-color: rgba(0, 0, 0, 0.5);':''">  
        <view style="width: 540rpx;height: 790rpx;border-radius: 24rpx;" class="">  
            <view style="width: 540rpx;height: 379rpx;">  
                <image style="width: 540rpx;height: 379rpx;" src="../../static/imgs/upDataModel.png"></image>  
            </view>  
            <view  
                style="width: 540rpx;height: 411rpx; background-color: #FFFFFF;border-radius: 0rpx 0rpx 24rpx 24rpx;position: relative;">  
                <view class="" style="flex-direction: row; justify-content: center;">  
                    <view class="title">{{lang == 'ch'?errorInfo.title:'New Version'}}</view>  
                    <view style="width: 32rpx;height: 32rpx;margin-left: 4rpx;">  
                        <image style="width: 32rpx;height: 32rpx;" src="../../static/imgs/upDataTips.png"></image>  
                    </view>  
                </view>  
                <view class="" style="margin-top: 35rpx; padding-left: 50rpx; padding-right: 50rpx;">  
                    <view style="flex-direction: row; width: 440rpx;" v-for="(item,index) in errorInfo.arr" :key="index">  
                        <text class="decs-text" style="width: 18rpx;">{{index 1}}</text>  
                        <text class="decs-text">、</text>  
                        <text class="decs-text" style="width: 400rpx;">{{item}}</text>  
                    </view>  
                </view>  
                <view class="flex_c_m" style="position: absolute;bottom: 40rpx;width: 540rpx;height: max-content;">  
                    <view class="bg-ebuy flex_c_m" style="width: 440rpx; height: 80rpx; border-radius: 10rpx;"  
                        @click="confirmprint">  
                        <text class="btn">{{lang == 'ch'?'立即更新':'Update Now'}}</text>  
                    </view>  
                    <text class="fs-22 pa-t12 fc-999">{{lang == 'ch'?"建议连接wifi更快哦":"It's faster to connect to wifi"}}</text>  
                </view>  
            </view>  
        </view>  
    </view>  
</template>  

<script>  
    import {  
        mapState  
    } from 'vuex';  
    import hotUpdate from '@/js_sdk/hot-update.js'  
    export default {  
        data() {  
            return {  
                setBac:false,  
                errorInfo:{  
                    title:'',  
                    arr:[]  
                }  
            }  
        },  
        computed: {  
            ...mapState({  
                lang: 'lang',  
            }),  
        },  
        created() {  
            // 在 subNVue/vue 页面注册事件监听方法    
            // $on(eventName, callback)    
            // 使用 uni.$off 移除之前事件监听器。  
            uni.$off('subPromptmsg', () => {})    
            // 用于接收拦截器发出的页面通信事件,用于接受拦截器发出的最新版本信息  
            uni.$on('subPromptmsg', (data) => {    
              this.setBac = data.setBac  
              this.errorInfo = data  
            })    
        },  
        methods: {  
            closeShowPopup() {  
                uni.$emit('popup', {  
                    isShow: false,  
                });  
            },  
                         //确认更新  
            confirmprint() {  
                uni.showLoading({  
                    title: this.lang == 'ch' ? '更新中...' : 'updating...'  
                })  
                uni.$emit('popup', {  
                    isShow: false,  
                });  
                hotUpdate.versionAutoUpdate(this.versionCode)  
            }  
        }  
    }  
</script>  

<style>  
    .btn {  
        font-size: 32rpx;  
        font-weight: 500;  
        color: #FFFFFF;  
        line-height: 45rpx;  
    }  

    .title {  
        font-size: 40rpx;  
        font-weight: 600;  
        color: #000000;  
        line-height: 56rpx;  
        /* #ifndef APP-NVUE */  
        letter-spacing: 4rpx;  
        /* #endif */  
    }  

    .decs-text {  
        font-size: 24rpx;  
        font-weight: 500;  
        color: #666666;  
        line-height: 40rpx;  
    }  
</style>  

仅为个人实现需求的方法,如有不对之处。欢迎大家进行审查和指正,并尽可能给出一些反馈和建议,以便改进代码的质量和可用性。

4 关注 分享
x***@163.com 4***@qq.com 蜗牛小弟 天空微算

要回复文章请先登录注册

w***@gmail.com

w***@gmail.com (作者)

回复 z***@hrbyulong.com :
子窗体接收到传值吗? setTimeout(() => {
const subNVue = uni.getSubNVueById('popup');
subNVue.show('slide-in-center', 200, () => {})
}, 1000) ,把这个slide-in-center换掉就好了
2023-08-10 15:11
z***@hrbyulong.com

z***@hrbyulong.com

请问在监听到子窗口传值之后怎么改变子窗口定位吗?
2023-07-29 19:19
x***@163.com

x***@163.com

6666
2023-05-17 09:17