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
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值