uni-app uni-popup 弹窗没有相对手机窗口弹起问题

uni-app uni-popup 弹窗没有相对手机窗口弹起问题

操作步骤:

点击自定义封装的组件触发uni-popup组件从手机底部弹起

预期结果:

从手机底部弹起,最高层级,点击蒙蔽收起底部弹窗

实际结果:

只有蒙蔽,弹窗内容添加在页面下方, 跟随页面滚动

bug描述:

组件内的uni-popup 组件出问题, 没有从手机底部弹起, 而是自己加在页面后面, 跟随页面滚动, 自身的定位没有相对于手机窗口  
信息项 内容
产品分类 uniapp/App
PC开发环境 Windows
PC操作系统版本 Windows 10 家庭中文版20H2,64 位操作系统, 基于 x64 的处理器
HBuilderX类型 正式
HBuilderX版本 3.2.9
手机系统 Android
手机系统版本 Android 10
手机厂商 华为
手机机型 HLK-AL00
页面类型 vue
打包方式 云端
项目创建方式 HBuilderX

Image Image Image


更多关于uni-app uni-popup 弹窗没有相对手机窗口弹起问题的实战教程也可以访问 https://www.itying.com/category-93-b0.html

2 回复

// 调用页面
<template>
<KXDateTime @rundata=‘kxdatetimeend’ :end=“endDate” :default="‘date’"></KXDateTime>

</template> // ------------------

// 组件内容
<template>
<view name='KXDateTime'>
<view :class=“dir == ‘right’ ? ‘list-row change dir-right’ : ‘list-row change’” @click=“open”>
<view class="hint">
{{changeDate == 0 ? ‘请选择’ : changeDate}}
</view>
<view class="iconfont icon-xiangyou1"></view>
</view>
<uni-popup ref="popup" type="bottom">
<view class="but">
<text @click=“close”>取消</text>
<text @click=“ok”>确定</text>
</view>
<picker-view v-if=“visible” :indicator-style=“indicatorStyle” :value=“value” @change=“bindChange”>
<picker-view-column>
<view class="item" v-for="(item,index) in years" :key="index">{{item}}年</view>
</picker-view-column>
<picker-view-column>
<view class="item" v-for="(item,index) in months" :key="index">{{item}}月</view>
</picker-view-column>
<picker-view-column>
<view class="item" v-for="(item,index) in days" :key="index">{{item}}日</view>
</picker-view-column>
<picker-view-column>
<view class="item" v-for="(item,index) in hours" :key="index">{{item}}时</view>
</picker-view-column>
<picker-view-column>
<view class="item" v-for="(item,index) in mins" :key="index">{{item}}分</view>
</picker-view-column>
</picker-view>

        <picker-view v-else :indicator-style="indicatorStyle" :value="value" @change="bindChange">  
            <picker-view-column>  
                <view class="item" v-for="(item,index) in years" :key="index">{{item}}年</view>  
            </picker-view-column>  
            <picker-view-column>  
                <view class="item" v-for="(item,index) in months" :key="index">{{item}}月</view>  
            </picker-view-column>  
            <picker-view-column>  
                <view class="item" v-for="(item,index) in days" :key="index">{{item}}日</view>  
            </picker-view-column>  
            <picker-view-column>  
                <view class="item" v-for="(item,index) in hours_num" :key="index">{{item}}号</view>  
            </picker-view-column>  
        </picker-view>  

    </uni-popup>  
</view>  
</template> <script> import uniPopup from '../uni-popup/uni-popup.vue' export default { name: 'KXDateTime', components: { uniPopup }, props: { isVisible: { type: Boolean, default: true }, dir: '', date: '', start: '', end: '', default: '', placeholder: '' }, data() { let defaultvalue = this.default; let value = [9999, 99, 99, 0, 0]; if (defaultvalue == 'end') { value = [9999, 99, 99, 0, 0] } else if (defaultvalue == 'start') { value = [0, 0, 0, 0, 0] } return { isChange: false, flang: true, changeDate: 0, title: 'picker-view', years: [], year: '', months: [], month: '', days: [], day: '', hours: [], hour: '', mins: [], min: '', hour_num: '', hours_num: [], value, valueStr: '', visible: true, strYMDHM: '', indicatorStyle: `height: 80rpx;`, trimer: null, } }, destroyed() { this.flang = true; }, methods: { slep(slep) { return new Promise((resolve, reject) => { setTimeout(() => { resolve(true) }, slep) }) }, async toData() { console.log('change') if (this.default == 'date') { let tempDate = new Date(); let y = tempDate.getFullYear(); let m = tempDate.getMonth(); let d = tempDate.getDate(); let temp = this.years.findIndex(item => item == y); let temp2 = this.months.findIndex(item => item == m); let temp3 = this.days.findIndex(item => item == d); this.value = [temp, temp2 + 1, temp3, 0, 0]; this.bindChange({ detail: { value: [temp, temp2 + 1, temp3, 0, 0] } }) if(temp3 == -1 || temp == -1 || temp2 == -1) { await this.slep(100); this.toData(); } } }, open() { let start; if (this.start) { start = this.start.replace(/-/g, "/") start = new Date(start); } else { start = new Date(0); } let starty = start.getFullYear(); //开始年份 let end; if (this.end) { end = this.end.replace(/-/g, "/") end = new Date(end); } else { end = new Date(); } if (start > end) { uni.showToast({ title: '时间范围错误!', icon: 'none', duration: 2000 }); return false } this.$forceUpdate(); if (this.valueStr) { this.value = JSON.parse(this.valueStr); setTimeout(() => { this.amend(); this.toData(); }, 100) this.$refs.popup.open() } else { setTimeout(() => { this.amend(); this.toData(); }, 100) this.$refs.popup.open() } let temp = []; for (var i = 0, len = 100; i <= len; i++) { temp.push(i) } this.hours_num = temp; }, close() { this.$refs.popup.close() }, ok() { let day = this.day < 10 ? '0' + this.day : this.day, month = this.month < 10 ? '0' + this.month : this.month, hour = this.hour < 10 ? '0' + this.hour : this.hour, min = this.min < 10 ? '0' + this.min : this.min if (!this.isVisible) { hour = this.hour_num < 10 ? '0' + this.hour_num : this.hour_num var data_ = this.year + ',' + month + ',' + day + ',' + hour this.changeDate = this.isChange ? data_ : this.end; this.$emit("update:number", data_) this.$refs.popup.close() return false; } let data = this.isChange ? this.year + '-' + month + '-' + day + ' ' + hour + ':' + min : this.end; this.changeDate = this.isChange ? data : this.end; this.$emit("rundata", data) this.$emit("update:model", data) this.$emit("update:model_ss", data + ':00') this.$refs.popup.close() }, bindChange: function(e) { this.isChange = true; let val = e.detail.value this.valueStr = JSON.stringify(val); this.year = this.years[val[0]] this.month = this.months[val[1]] this.day = this.days[val[2]] this.hour = this.hours[val[3]]; this.hour_num = this.hours_num[val[3]]; this.min = this.mins[val[4]] }, //数据校正 amend() { if (this.valueStr) { let val = JSON.parse(this.valueStr); this.year = this.years[val[0]] this.month = this.months[val[1]] this.day = this.days[val[2]] this.hour = this.hours[val[3]] this.min = this.mins[val[4]] } let start; if (this.start) { start = this.start.replace(/-/g, "/") start = new Date(start); } else { start = new Date(0); } let starty = start.getFullYear(); //开始年份 let startm = start.getMonth() + 1; //开始月份 let startd = start.getDate(); //开始天 let starth = start.getHours(); //开始小时 let startmin = start.getMinutes(); //开始分钟 let end; if (this.end) { end = this.end.replace(/-/g, "/") end = new Date(end); } else { end = new Date(); } let endy = end.getFullYear(); //终止年份 let endm = end.getMonth() + 1; //终止月份 let endd = end.getDate(); //终止天 let endh = end.getHours(); //终止小时 let endmin = end.getMinutes(); //终止分钟 //如果选择起始年份 let years = [], months = [], days = [], hours = [], mins = []; let month31 = [1, 3, 5, 7, 8, 10, 12], month30 = [4, 6, 9, 11]; let daysNum; for (let i = starty; i <= endy; i++) { years.push(i) } if (month31.indexOf(this.month) > -1) { daysNum = 31 } else if (month30.indexOf(this.month) > -1) { daysNum = 30 } else { if (this.year % 4 == 0) { daysNum = 29 } else { daysNum = 28 } } let defaultvalue = this.default; let defaulty = endy, defaultm = endm, defaultd = endd, defaulth = endh, defaultmin = endmin; if (defaultvalue == 'end') { defaulty = endy; defaultm = endm; defaultd = endd; defaulth = endh; defaultmin = endmin; } else if (defaultvalue == 'start') { defaulty = starty; defaultm = startm; defaultd = startd; defaulth = starth; defaultmin = startmin; } //当数值异常是设施默认 if (!this.year) { this.year = defaulty } if (!this.month) { this.month = defaultm } if (!this.day) { this.day = defaultd } if (!this.hour && this.hour !== 0) { this.hour = defaulth } if (!this.min && this.min !== 0) { this.min = defaultmin } //判断年份是在起始年 if (this.year == starty) { //判断起始年份和终止年份是否相等 if (starty == endy) { //如果等,那么月份取两者中间 for (let i = startm; i <= endm; i++) { months.push(i) } //判断月份是在起始月 if (this.month == startm) { //判断起始月和终止月是否相等 if (startm == endm) { //如果等,那么天数取两者中间 for (let i = startd; i <= endd; i++) { days.push(i) } //判断日是在起始日 if (this.day == startd) { //判断起始ri和终止日是否相等 if (startd == endd) { //如果等,那么小时取两者中间 for (let i = starth; i <= endh; i++) { hours.push(i) } //判断小时是在起始小时 if (this.hour == starth) { //判断起始和终止是否相等 if (starth == endh) { //如果等,那么分钟取两者中间 for (let i = startmin; i <= endmin; i++) { mins.push(i) } } else { //如果不等,到59 for (let i = startmin; i <= 59; i++) { mins.push(i) } } } else { //判断小时是否在截止小时 if (this.hour == endh) { //终止小时取到截止分钟 for (let i = 0; i <= endmin; i++) { mins.push(i) } } } } else { //如果不等,到23小时 for (let i = starth; i <= 23; i++) { hours.push(i) } //判断小时是在起始小时 if (this.hour == starth) { for (let i = startmin; i <= 59; i++) { mins.push(i) } } } } else { //判断日是否在截止日 if (this.day == endd) { //终止日取到截止小时 for (let i = 0; i <= endh; i++) { hours.push(i) } //判断小时是否在截止小时 if (this.hour == endh) { //终止小时取到截止分钟 for (let i = 0; i <= endmin; i++) { mins.push(i) } } } } } else { //如果不等, for (let i = startd; i <= daysNum; i++) { days.push(i) } if (this.day == startd) { for (let i = starth; i <= 23; i++) { hours.push(i) } //判断小时是在起始小时 if (this.hour == starth) { for (let i = startmin; i <= 59; i++) { mins.push(i) } } } } } else { //判断月份是在终止月 if (this.month == endm) { //终止月取到截止天 for (let i = 1; i <= endd; i++) { days.push(i) } //判断日是否在截止日 if (this.day == endd) { //终止日取到截止小时 for (let i = 0; i <= endh; i++) { hours.push(i) } //判断小时是否在截止小时 if (this.hour == endh) { //终止小时取到截止分钟 for (let i = 0; i <= endmin; i++) { mins.push(i) } } } } } } else { //如果不等,去开始到12月份 for (let i = startm; i <= 12; i++) { months.push(i) } //判断月份是在起始月 if (this.month == startm) { //是,取天数之后 for (let i = startd; i <= daysNum; i++) { days.push(i) } //判断日是在起始日 if (this.day == startd) { //是,qu起始小时之后 for (let i = starth; i <= 23; i++) { hours.push(i) } //判断小时是在起始小时 if (this.hour == starth) { //是,qu起始分钟之后 for (let i = startmin; i <= 59; i++) { mins.push(i) } } } } } } else if (this.year == endy) { //年份中终止年 //月份取到终止月 for (let i = 1; i <= endm; i++) { months.push(i) } //判断月份是在终止月 if (this.month == endm) { //终止月取到截止天 for (let i = 1; i <= endd; i++) { days.push(i) } //判断日是否在截止日 if (this.day == endd) { //终止日取到截止小时 for (let i = 0; i <= endh; i++) { hours.push(i) } //判断小时是否在截止小时 if (this.hour == endh) { //终止小时取到截止分钟 for (let i = 0; i <= endmin; i++) { mins.push(i) } } } } } else { for (let i = 1; i <= 12; i++) { months.push(i) } for (let i = 1; i <= daysNum; i++) { days.push(i) } for (let i = 0; i <= 23; i++) { hours.push(i) } for (let i = 0; i <= 59; i++) { mins.push(i) } } if (months.length == 0) { for (let i = 1; i <= 12; i++) { months.push(i) } } if (days.length == 0) { for (let i = 1; i <= daysNum; i++) { days.push(i) } } if (hours.length == 0) { for (let i = 0; i <= 23; i++) { hours.push(i) } } if (mins.length == 0) { for (let i = 0; i <= 59; i++) { mins.push(i) } } this.years = years; this.months = months; this.days = days; this.hours = hours; this.mins = mins; this.$forceUpdate(); } }, watch: { isVisible: { handler(val) { this.visible = val; }, immediate: true }, year(val) { console.log(val) this.amend(); }, month() { this.amend(); }, day() { this.amend(); }, hour() { this.amend(); }, min() { this.amend(); // if(this.flang){ // this.toData(); // } // this.flang = false; }, years(n, m) { if (n.toString() != m.toString()) { this.amend(); } }, months(n, m) { if (n.toString() != m.toString()) { this.amend(); } }, days(n, m) { if (n.toString() != m.toString()) { this.amend(); } }, hours(n, m) { if (n.toString() != m.toString()) { this.amend(); } }, mins(n, m) { if (n.toString() != m.toString()) { this.amend(); } } } } </script> <style lang="scss" scoped> text { display: inline-block; color: $uni-text-color-grey; } .item { display: flex; align-items: center; justify-content: center; } .change { display: flex; justify-content: space-between; margin-top: 24rpx; .hint { font-size: 28rpx; font-family: PingFangSC-Regular, PingFang SC; font-weight: 400; color: #8F9399; line-height: 40rpx; } .iconfont { display: flex; align-items: center; color: #606265; font-size: 26rpx; } &.dir-right { flex: 1; margin-top: 0; justify-content: flex-end; } } .but { background: #fff; height: 80rpx; line-height: 80rpx; padding: 0 30rpx; border-bottom: 1px solid #f0f0f0; text-align: left; text { display: inline-block; } text:last-child { float: right; color: $uni-color-primary; } } picker-view { width: 100%; background: #fff; height: 600rpx; text-align: center; } </style>

更多关于uni-app uni-popup 弹窗没有相对手机窗口弹起问题的实战教程也可以访问 https://www.itying.com/category-93-b0.html


这个问题通常是由于 uni-popup 组件的父元素存在定位或样式层级问题导致的。根据你的描述,弹窗内容没有相对于手机窗口定位,而是跟随页面滚动,这很可能是因为弹窗被嵌套在了具有滚动或定位属性的父容器内。

主要原因和解决方案:

  1. 检查父容器定位:确保 uni-popup 的直接父元素没有设置 position: relativeposition: absoluteoverflow 属性。这些样式会影响弹窗的定位层级。建议将 uni-popup 放在页面根节点下,避免嵌套在复杂布局中。

  2. 使用正确的弹出模式uni-popup 支持多种弹出类型(如 bottomcentertop)。确认你调用的是 type="bottom" 的底部弹出模式。示例代码:

    <uni-popup ref="popup" type="bottom">
      <!-- 弹窗内容 -->
    </uni-popup>
    
  3. 检查组件引入和版本:确保使用的是官方最新版本的 uni-popup 组件(可通过 HBuilderX 的“插件市场”更新)。旧版本可能存在兼容性问题。

  4. 避免样式冲突:检查全局或局部 CSS 是否覆盖了 uni-popup 的默认样式(如 z-indexposition)。弹窗的 z-index 默认较高(通常为 999),但若父容器层级限制,可能导致弹窗无法置顶。

  5. 使用官方示例验证:创建一个最简单的测试页面,仅包含 uni-popup 组件,排除其他代码干扰。如果测试正常,则说明原页面存在样式或结构冲突。

临时解决方案
如果问题紧急,可以尝试强制修改弹窗样式,例如在弹窗内容上添加内联样式:

<uni-popup ref="popup">
  <view style="position: fixed; bottom: 0; left: 0; right: 0; z-index: 1000;">
    <!-- 内容 -->
  </view>
</uni-popup>
回到顶部