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'
                })
            }
        });

效果

相关推荐
社恐的下水道蟑螂3 小时前
从字符串到像素:深度解析 HTML/CSS/JS 的页面渲染全过程
javascript·css·html
程序定小飞3 小时前
基于springboot的web的音乐网站开发与设计
java·前端·数据库·vue.js·spring boot·后端·spring
Hello_WOAIAI3 小时前
2.4 python装饰器在 Web 框架和测试中的实战应用
开发语言·前端·python
FinClip3 小时前
凡泰极客亮相香港金融科技周,AI助力全球企业构建超级应用
前端
阿四3 小时前
【Nextjs】为什么server action中在try/catch内写redirect操作会跳转失败?
前端·next.js
申阳3 小时前
Day 6:04. 基于Nuxt开发博客项目-LOGO生成以及ICON图标引入
前端·后端·程序员
中国lanwp4 小时前
npm中@your-company:registry 和 registry 的区别
前端·npm·node.js
Bacon4 小时前
Electron 应用商店:开箱即用工具集成方案
前端·github
行走的陀螺仪4 小时前
uni-app + Vue3 实现折叠文本(超出省略 + 展开收起)
前端·javascript·css·uni-app·vue3
冴羽4 小时前
JavaScript 异步循环踩坑指南
前端·javascript·node.js