在一个自定义组件里放置多个uni-popup会默认显示最后一个uni-popup而不是指定的uni-popup

在一个自定义组件里放置多个uni-popup会默认显示最后一个uni-popup而不是指定的uni-popup

操作步骤:

  • 点击支付按钮,给iPopupPay的show传true

预期结果:

  • 显示iPopupPay支付弹窗

实际结果:

  • 显示iPromptDialog提示弹窗

bug描述:

自定义组件iPopupPay.vue【支付弹窗】使用uni-popup实现,该组件下包含其他的弹出组件(也是使用uni-popup实现),当【支付弹窗】的show=true的时候,没有弹出支付弹窗,而是弹出最后一个弹窗iPromptDialog【无密码弹窗】,但iPromptDialog的控制标记showNoPwd一直都是false;如果删除iPromptDialog那段代码,重复一遍,依然不会弹出【支付弹窗】,而是弹出最后一个弹窗iPromptDialog【支付结果弹窗】,但showModal的值一直是false。

在iPopupPay组件里监听show,调用uni-popup的open方法显示弹窗。

props: {  
    show: {  
        type: Boolean,  
        default: false,  
        required: true  
    },  
    order: {  
        type: Object,  
        required: true  
    },  
},  
data() {  
    return {  
        showPassword: false,  
        showModal: false,  
        showNoPwd: false,  
        amount: '0.00',  
        balance: '0.00',  
        payType: 'balance',  
        hasPassword: false  
    };  
},  
watch: {  
    show: function(prop) {  
        console.log('iPopupPay', prop)  
        if (prop) {  
            console.log('====this.$refs.popup.open()=====', this.showNoPwd)  
            this.$refs.popup.open()  
            this.amount = (this.isDesposit ? this.order.depositPrice : this.order.balancePayment) ?? '0.00'  
        }  
    }  
},
<template>  
    <view @touchmove.stop.prevent="moveHandle">  
        <uni-popup ref='popup' type='bottom' border-radius="32rpx 32rpx 0 0" background-color="#fff"  
        @maskClick="change">  
            <view>  
            //支付弹窗内容  
            </view>  
        </uni-popup>  
    <iPopupPassword v-model:show="showPassword" @result='handlePassword'></iPopupPassword>  
    <iPromptDialog v-model:show="showModal" title='支付提示' message='该笔订单是否支付成功?' confirmText='已支付'  cancelText='未支付'  @confirm='payOk'></iPromptDialog>  
    <iPromptDialog v-model:show="showNoPwd" title='提示' message='您还未设置支付密码,是否前去设置?' confirmText='设置'   cancelText='取消' @confirm='gotoPwd'></iPromptDialog>  
</template>

在OrderList.vue里引用iPopupPay组件

<iPopupPay v-model:show='showPay' :order='order'></iPopupPay>

表格

信息类别 内容
产品分类 uniapp/小程序/抖音
PC开发环境 Windows
操作系统版本号 Windows 10 专业工作站版 版本号 2009 安装日期 ‎2023/‎11/‎12 OS 内部版本 19045.5965
HBuilderX类型 正式
HBuilderX版本号 4.66
第三方开发者工具版本号 4.4.1
基础库版本号 3.68.0.5
项目创建方式 HBuilderX

2 回复

BUG原因找到了,因为我在每个uni-popup的自定义组件中,uni-popup的ref都设置为popup,当在iPopupPay里调用this.$refs.popup.open()显示弹窗时,this.$refs.popup被指向最后一个撰写的uni-popup的ref。但是这样的写法在微信小程序里是正常的,只有抖音小程序出现这样的错误。


这是因为在同一个自定义组件中使用了多个 uni-popup 组件时,默认情况下它们会共享同一个弹出层实例。当调用 this.$refs.popup.open() 时,系统会显示最后创建的 uni-popup 实例,而不是你指定的支付弹窗。

解决方案:

  1. 为每个 popup 指定不同的 ref 修改模板中的 ref 命名,确保每个 uni-popup 都有唯一的 ref 标识:
<uni-popup ref='popupPay' type='bottom'>支付弹窗内容</uni-popup>
<uni-popup ref='popupModal'><iPromptDialog>...</iPromptDialog></uni-popup>
<uni-popup ref='popupNoPwd'><iPromptDialog>...</iPromptDialog></uni-popup>
  1. 在 watch 中调用正确的 ref 更新 watch 中的代码,明确调用支付弹窗的 ref:
watch: {
    show: function(prop) {
        if (prop) {
            this.$refs.popupPay.open()  // 明确指定打开支付弹窗
            this.amount = (this.isDesposit ? this.order.depositPrice : this.order.balancePayment) ?? '0.00'
        }
    }
}
回到顶部