<template> <view class="next-bubble-menu" > <view @click.stop="showContainer"> <slot></slot> </view> <view class="mask" v-show="show && showUi" @click.stop="show=false"></view> <view class="container" v-show="show && showUi"> <view class="block" :style="{left: `calc(50% - ${(width*0.5).toFixed(0)}rpx)`}"> <view class="arrow" :style="{ left:0, top: showTop && (arrowTop+12)+'rpx' }" @click.stop> </view> <view class="list-container" :style="'height:'+(dHeight?dHeight+'rpx':'auto')+';max-height:'+dMaxHeight+'rpx;border-radius:'+radius+'rpx;width:'+width+'rpx;left:'+ relativeAllow +'rpx;'"> <view :class="'list-item '+(index==dataList.length-1?'':'bt')" v-for="(item,index) in dataList" :key="index" @click.stop="clickItem(item)"> <image class="list-item-image" :src="item.iconSrc" v-if="item.iconSrc" /> <text class="list-item-text">{{item.text}}</text> </view> </view> </view> </view> </view> </template> <script> let closeOtherHooks = new Set() const closeOtherPopUp = (closePopUp) => { closeOtherHooks.forEach(hook => { if (closePopUp !== hook) { //closePopUp当前页面关闭方法,hook所有页面的关闭方法 hook() } }) } export default { props: { bingEleId: { type: String, default: '' }, //气泡框数据源 dataList: { type: Array, default: () => { return [] } }, hasBar: { type: Boolean, default: true }, radius: { type: Number, default: 8 }, dWidth: { type: Number, default: 0 }, dHeight: { type: Number, default: 0 }, dMaxHeight: { type: Number, default: 400 }, relativeAllow: { type: Number, default: -30 } }, data() { return { show: false, width: 0, height: 0, left: 0, top: 0, bottom: 0, rectTop: 0, screenWidth: 0, showTop: false, arrowTop: 0, showUi: false } }, mounted() { const closePopUp = () => { this.show = false; } closeOtherHooks.add(closePopUp) //closeOtherHooks每个页面的关闭方法都加上 this.closePopUp = closePopUp this.$nextTick(() => { if (!this.bingEleId) return // #ifdef APP-PLUS uni.createSelectorQuery().in(this).select('.next-bubble-menu').boundingClientRect(res => { let difference = res.left uni.createSelectorQuery().select('#' + this.bingEleId).boundingClientRect(rect => { const systemInfo = uni.getSystemInfoSync() const windowHeight = systemInfo.windowHeight this.screenWidth = systemInfo.screenWidth if (!this.dWidth) { this.width = this.px2rpx(rect.width, this.screenWidth) } else { let screenW = this.px2rpx(this.screenWidth, this.screenWidth) this.width = this.dWidth > screenW ? screenW : this.dWidth } this.height = rect.height this.rectTop = rect.top this.bottom = windowHeight - rect.bottom }).exec() }).exec() // #endif // #ifndef APP-PLUS uni.createSelectorQuery().in(this).select('.next-bubble-menu').boundingClientRect(res => { let difference = res.left uni.createSelectorQuery().select('#' + this.bingEleId).boundingClientRect(rect => { const systemInfo = uni.getSystemInfoSync() const windowHeight = systemInfo.windowHeight this.screenWidth = systemInfo.screenWidth if (!this.dWidth) { this.width = this.px2rpx(rect.width, this.screenWidth) } else { let screenW = this.px2rpx(this.screenWidth, this.screenWidth) this.width = this.dWidth > screenW ? screenW : this.dWidth } this.height = rect.height this.rectTop = rect.top this.bottom = windowHeight - rect.bottom }).exec() }).exec() // #endif }) }, methods: { showContainer() { if (!this.bingEleId) return else this.show = !this.show if (this.show) { closeOtherPopUp(this.closePopUp) //关掉其他的 this.$nextTick(res => { // #ifdef APP-PLUS let view = uni.createSelectorQuery().in(this).select(".list-container") view.boundingClientRect(res => { let arrHeight = res.height let height = this.bottom - arrHeight - 15 if (height < 0) { this.showTop = true this.top = this.px2rpx((this.rectTop - arrHeight - 10), this .screenWidth) this.arrowTop = this.px2rpx(arrHeight - 5, this.screenWidth) } else { this.showTop = false this.top = this.px2rpx(this.rectTop + this.height + 10, this .screenWidth) } this.$nextTick(() => { this.showUi = true }) }).exec() // #endif // #ifndef APP-PLUS uni.createSelectorQuery().in(this).select('.list-container').boundingClientRect(res => { const left = res.left let arrHeight = res.height let height = this.bottom - arrHeight - 15 if (height < 0) { this.showTop = true if (this.hasBar) { // #ifdef H5 this.top = this.px2rpx((this.rectTop - arrHeight + 35), this .screenWidth) // #endif // #ifndef H5 this.top = this.px2rpx((this.rectTop - arrHeight - 10), this .screenWidth) // #endif } else { this.top = this.px2rpx((this.rectTop - arrHeight - 10), this .screenWidth) } this.arrowTop = this.px2rpx(arrHeight - 5, this.screenWidth) } else { this.showTop = false if (this.hasBar) { // #ifdef H5 this.top = this.px2rpx(this.rectTop + this.height + 54, this .screenWidth) // #endif // #ifndef H5 this.top = this.px2rpx(this.rectTop + this.height + 10, this .screenWidth) // #endif } else { this.top = this.px2rpx(this.rectTop + this.height + 10, this .screenWidth) } } this.$nextTick(() => { this.showUi = true }) }).exec() // #endif }) } }, px2rpx(px, screenWidth) { return px / (screenWidth / 750) }, //点击选项 clickItem(item) { this.show = false this.$emit('change', item) } } } </script> <style lang="scss" scoped> $bgColor:#3da7e7; $ftColor:#ffffff; .mask{ position: fixed; top: 0; left: 0; right: 0; bottom: 0; z-index: 999999 !important; // background:rgba(0, 0, 0, 0.5); } .next-bubble-menu { position: relative; border: solid transparent 1px; } .block { /* position: fixed; */ position: absolute; z-index: 99999999 !important; } .container{ position: relative; } .list-container { box-sizing: border-box; overflow: auto; // padding: 16rpx 20rpx; background-color: $bgColor; box-shadow: 2rpx 4rpx 10rpx rgba(0,0,0,.1); } .arrow { width: 0; height: 0; margin: -10rpx auto 0; border-top: 10rpx solid transparent; border-bottom: 10rpx solid $bgColor; border-right: 10rpx solid transparent; border-left: 10rpx solid transparent; } .list-item { line-height: 80rpx; text-align: center; color: $ftColor; &:active{ background-color:$ftColor; color: $bgColor; } } .bt{ border-bottom: 1px solid $ftColor; } .list-item .list-item-image { display: inline-block; vertical-align: middle; width: 40rpx; height: 40rpx; margin-right: 20rpx; } .list-item .list-item-text { vertical-align: middle; } </style>