uni-app vue 全局模态框

Uni-app Vue全局模态框

思路是将模态框作为一个页面,进而可以全局显示
首先创建一个页面用来显示模态框 u-modal
<!-- pages/popup/showModal.vue -->
<template>
    <view>
        <!-- 使用uViewUI的u-modal -->
        <u-modal
            v-model="showModel"
            @confirm="confirm"
            @cancel="cancel"
            :show-cancel-button="true"
            :title="options.title"
            confirm-text="Confirm"
            cancel-text="Cancel"
            :show-title="options.title != null && options.title !== ''"
            :title-style="{
                'font-size': '40rpx',
            }"
        >
            <view class="modelContent">
                <view>
                    <u-icon
                        name="question-circle"
                        color="#faad14"
                        size="38"
                        class="icon"
                    ></u-icon>
                    {{ options.content }}
                </view>
            </view>
        </u-modal>
    </view>
</template>
<script lang="ts">
import { defineComponent, reactive, toRefs } from '@vue/composition-api'

export default defineComponent({
    onLoad(options: any) {
        // 获取配置
        this.options = options
    },
    setup() {
        const data = reactive({
            showModel: true,
            result: {
                confirm: false,
                cancel: false,
            },
            modelTitle: '',
            options: {
                title: '',
                content: '',
            } as Partial<UniApp.RedirectToOptions>,
        })
        let { showModel, result, modelTitle, options } = toRefs(data)
        const closeModel = () => {
            // 执行操作后,发布事件同时返回原来页面
            uni.$emit('myModelResult', result)
            uni.navigateBack({
                delta: 1,
            })
        }
        const cancel = () => {
            result.value.cancel = true
            closeModel()
        }
        const confirm = () => {
            result.value.confirm = true
            closeModel()
        }
        return {
            closeModel,
            showModel,
            result,
            cancel,
            confirm,
            modelTitle,
            options,
        }
    },
})
</script>
<style>
/* 需要设置页面背景透明 */
page {
    background: transparent;
}
</style>
<style lang="scss" scoped>
.modelContent {
    padding: 30rpx 30rpx;
    text-align: center;
    .icon {
        margin-right: 30rpx;
    }
}
</style>

配置 pages.json
{
    "pages": [
    	...
		{
            "path": "pages/popup/showModal",
            "style": {
                "navigationStyle": "custom", // 取消默认的原生导航栏
                "backgroundColor": "transparent", // 设置透明背景
                "app-plus": {
                    "animationType": "fade-in", // 设置窗口动画
                    "background": "transparent", // 设置透明背景
                    "popGesture": "none" // 禁用侧滑返回
                }
            }
        }
    ],
    ...
}
执行函数
// showModal.ts
interface ShowModalRes {
    /**
     * 为 true 时,表示用户点击了确定按钮
     */
    confirm: boolean;
    /**
     * 为 true 时,表示用户点击了取消
     */
    cancel: boolean;
}

export interface ShowModalOptions {
    /**
     * 提示的标题
     */
    title?: string;
    /**
     * 提示的内容
     */
    content?: string;
    /**
     * 接口调用成功的回调函数
     */
    success?: (result: ShowModalRes) => void;
    /**
     * 接口调用失败的回调函数
     */
    fail?: (result: any) => void;
    /**
     * 接口调用结束的回调函数(调用成功、失败都会执行)
     */
    complete?: (result: any) => void;
}
export const showModal = function (options: ShowModalOptions): void {
    // #ifdef APP-PLUS
    // 目前仅支持App端
    try {
        uni.navigateTo({
            url: param('/pages/popup/showModal', {
                title: options.title,
                content: options.content
            })
        })
        // 触发一次
        uni.$once('myModelResult', refImpl => {
            if (options.success && typeof options.success === 'function') {
                options.success.call(null, refImpl.value as ShowModalRes)
            }
        })
    } catch (err) {
        if (options.fail && typeof options.fail === 'function') {
            options.fail.call(null, err)
        }
    } finally {
        if (options.complete && typeof options.complete === 'function') {
            options.complete.call(null, {})
        }
    }
	// #endif
	// #ifndef APP-PLUS
	// 非 App 端,暂时无法做到背景透明,使用原生模态框
	uni.showModal(options)
	// #endif
}
// 参数拼接
function param(url: string, data: any) {
    let param = ''
    for (let k in data) {
        let value = data[k] != null ? data[k] : ''
        param += '&' + k + '=' + encodeURIComponent(value)
    }

    url += url.indexOf('?') < 0 ? '?' : '&'
    url += param ? param.substring(1) : ''
    return url
}
注入到 vue
// plugin.ts
import { showModal } from './showModal'

export default {
    install(Vue: any) {
        ...
        Vue.prototype.$showModal = showModal
    }
}
声明
// main.ts
declare module 'vue/types/vue' {
    // 为 Vue 声明 
    interface Vue {
        ...
        $showModal: (options: ShowModalOptions) => void
    }
}
import Vue from 'vue'
import App from './App.vue'
import plugin from './plugin/plugin'
    
...
Vue.use(plugin);

new App().$mount()
使用
this.$showModal({
    title: 'title'
    content: 'content',
    success: (res) => {
        if (res.confirm) {
            ...
        }
    }
})
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值