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

效果

相关推荐
顾辰呀11 分钟前
实现uniapp-微信小程序 搜索框+上拉加载+下拉刷新
前端·windows
hjt_未来可期19 分钟前
vue输入中文,获取英文首字母缩写
javascript·vue.js·ecmascript
前端Hardy24 分钟前
HTML&CSS:爱上班的猫咪
前端·javascript·css·vue.js·html
EricWang135824 分钟前
[OS] 项目3入手
java·linux·前端
烟雨666_java33 分钟前
csrf令牌
android·前端·csrf
2401_858120531 小时前
Spring Boot框架下的教育导师匹配系统
java·前端·spring boot
王解1 小时前
Jest项目实战(2): 项目开发与测试
前端·javascript·react.js·arcgis·typescript·单元测试
齐 飞1 小时前
MongoDB笔记03-MongoDB索引
前端·数据库·笔记·后端·mongodb
寰梦1 小时前
vue前端sku实现
前端·javascript·vue.js
shenweihong1 小时前
javascript实现国密hash(sm3)算法(支持微信小程序),可分多次计算
javascript·哈希算法