uni-app全局弹窗的实现方案

背景

为了解决uni-app 任意位置出现弹窗

解决方案

一、最初方案

受限于uni-app 调用组件需要每个页面都引入注册才可以使用,此方案繁琐,每个页面都要写侵入性比较强

二、改进方案

app端:新建一个页面进行跳转,可以实现伪弹窗(其实是打开一个背景透明的页面)

web端: 全局挂载body 插入一个弹窗

三、初步实现方案

就是 利用条件编译,web端写组件、app 端写页面,利用不同的生命周期,完成通用的逻辑

四、详细实现方案

1、完成弹窗页面开发

统一暴露一个show 方法,app 端使用 onload 监听事件触发,web端使用 show 方法触发

复制代码
    <template>
    <u-popup id="globalPopup-box" :show="params.show" :mode="params.mode" bgColor="transparent"
        @close="cancelSubmit(true)">
        <template v-if="params.type === 1">
            <view class="globalPopupContent" :class="{ globalPopupContentCenter: params.mode == 'center' }">
                <view class="title">{{ params.title }}</view>
            </view>
        </template>
        <template v-else>
            <view class="globalPopupContent" :class="{ globalPopupContentCenter: params.mode == 'center' }">
                <view class="title">{{ params.title }}</view>
            </view>
        </template>
    </u-popup>
</template>

<script>
export default {
    name: "globalPopup",
    data() {
        return {
            eventChannel: null,
            params: {},
        }
    },
    // #ifdef APP-PLUS
    onLoad() {
        this.eventChannel = this.getOpenerEventChannel();
        this.eventChannel.on('globalPopup', (data) => {
            console.log('globalPopup:', data)
            this.init(data)
        })
    },
    // #endif
    methods: {
        init(data) {
            this.params = data
            // 通用逻辑写在这里
        },
        // #ifdef H5
        show(data) {
            console.log('H5globalPopup:', data)
            this.init(data)
        },
        // #endif
        cancel() {
            // #ifdef APP-PLUS
            let _this = this;
            uni.navigateBack({
                delta: 1,
                success() {
                    _this.eventChannel.emit('cancel');
                }
            })
            // #endif

            this.hide()
            // #ifdef APP-PLUS
            this.params.cancel && this.params.cancel();
            // #endif

        },
        confirm() {
            // #ifdef APP-PLUS
            let _this = this;
            uni.navigateBack({
                delta: 1,
                success() {
                    _this.eventChannel.emit('confirm');
                }
            })
            // #endif

            this.hide();
            // #ifdef APP-PLUS
            this.params.confirm && this.params.confirm();
            // #endif

        },
        hide() {
            setTimeout(() => {
                this.params = {}
            }, 100)
        }
    }
}
</script>

<style>
page {
    background: transparent;
}
</style>

2、页面路由配置

复制代码
,{
            "path" : "components/globalPopup/globalPopup",
            "style": {
                "navigationStyle": "custom",
                "backgroundColor": "transparent",
                "app-plus": {
                    "animationType": "fade-in",
                    "background": "transparent",
                    "popGesture": "none",
                    "bounce": "none",
                    "titleNView": false
                }
            }
        },          

3、main.js中全局挂载 globalPopup.js

globalPopup.js

复制代码
const install = Vue => {
    Vue.prototype.$globalPopup = {
        show(params) {
            let pointPageUrl = getCurrentPages()[getCurrentPages().length - 1].route;
            if (pointPageUrl == 'components/globalPopup/globalPopup') return
            uni.navigateTo({
                url: '/components/globalPopup/globalPopup',
                success: function (res) {
                    // 利用事件 通知 目标页面
                    res.eventChannel.emit('globalPopup', params)
                }
            })
        }
    }
}
export default install;

main.js 的编码 条件编译

复制代码
// #ifdef APP-PLUS
import globalPopupjs from '@/components/globalPopup/globalPopup.js';
Vue.use(globalPopupjs);
// #endif

// #ifdef H5
import globalPopup from '@/components/globalPopup/globalPopup.vue'
const PopupVue = Vue.extend(globalPopup);
const popupDom = new PopupVue();
Vue.prototype.$globalPopup = popupDom.$mount();
const lastEl = document.body.lastElementChild;
if (lastEl.id !== 'globalPopup-box') {
    setTimeout(() => {
        document.body.appendChild(Vue.prototype.$globalPopup.$el)
    }, 0)
}
// #endif

4、如何任意位置出现弹窗

利用接口触发,返回相关弹窗配置

接口触发逻辑

复制代码
if (data.pop) {
    uni.$emit('showMyPopup', data.pop)
 }

监听逻辑

复制代码
// 监听事件
        uni.$on('showMyPopup', (pop) => {
            if (!this.isShowGlobalPopup) {
                console.log(pop, 'showMyPopup')
                let {
                    userQuestionStyleValue, // 样式值 1底部弹窗 2页中弹窗
                    userQuestionTemplateValue, // 模板值 1是否类 2打分类,
                    userQuestionInfo,
                    userQuestionAnswerDTO,
                } = pop
                this.$globalPopup.show({
                    id: pop.id,
                    show: true,
                    type: userQuestionTemplateValue == '1' ? 1 : 2,
                    userQuestionInfo,
                    title: userQuestionInfo.questionName,
                    userQuestionAnswerDTO,
                    mode: userQuestionStyleValue == '1' ? 'bottom' : 'center'
                })
            }
        });

效果

相关推荐
天天向上102412 分钟前
Vue 配置打包后可编辑的变量
前端·javascript·vue.js
芬兰y28 分钟前
VUE 带有搜索功能的穿梭框(简单demo)
前端·javascript·vue.js
好果不榨汁34 分钟前
qiankun 路由选择不同模式如何书写不同的配置
前端·vue.js
小蜜蜂dry35 分钟前
Fetch 笔记
前端·javascript
拾光拾趣录36 分钟前
列表分页中的快速翻页竞态问题
前端·javascript
小old弟37 分钟前
vue3,你看setup设计详解,也是个人才
前端
Lefan41 分钟前
一文了解什么是Dart
前端·flutter·dart
Patrick_Wilson1 小时前
青苔漫染待客迟
前端·设计模式·架构
vvilkim1 小时前
Nuxt.js 全面测试指南:从单元测试到E2E测试
开发语言·javascript·ecmascript
写不出来就跑路1 小时前
基于 Vue 3 的智能聊天界面实现:从 UI 到流式响应全解析
前端·vue.js·ui