You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

315 lines
7.8 KiB
Vue

<template>
<view class="ui-popover" :class="popover ? 'show' : 'hide'">
<view
class="ui-popover-button"
:class="[ui]"
:id="'popover-button-' + elId"
:style="{ zIndex: index + zIndexConfig.popover }"
@tap="popoverClick"
@mouseleave="mouseleave"
@mouseover="mouseover"
>
<slot></slot>
</view>
<view class="ui-popover-box" :style="BoxStyle">
<view class="ui-popover-content-box" :id="'popover-content-' + elId" :style="contentStyle">
<view
class="ui-popover-content radius text-a"
:class="bg"
:style="{ zIndex: index + zIndexConfig.popover + 2 }"
>
<view class="p-3 text-sm" v-if="tips">{{ tips }}</view>
<block v-else><slot name="content" /></block>
</view>
<view class="ui-popover-arrow" :class="bg" :style="arrowStyle"></view>
</view>
</view>
<view
class="ui-popover-mask"
:class="mask ? 'bg-mask-50' : ''"
:style="{ zIndex: index + zIndexConfig.popover - 1 }"
@tap="popover = false"
v-if="(popover && tips == '' && time == 0) || mask"
></view>
</view>
</template>
<script>
import { guid } from '@/sheep/helper';
import zIndexConfig from '@/sheep/config/zIndex.js';
import sheep from '@/sheep';
export default {
name: 'suPopover',
data() {
return {
elId: guid(),
zIndexConfig,
popover: false,
BoxStyle: '',
contentStyle: '',
arrowStyle: '',
button: {},
content: {},
};
},
props: {
ui: {
type: String,
default: '',
},
tips: {
type: String,
default: '',
},
bg: {
type: String,
default: 'ui-BG',
},
mask: {
type: Boolean,
default: false,
},
show: {
type: [Boolean, String],
default: 'change',
},
hover: {
type: Boolean,
default: false,
},
index: {
type: Number,
default: 0,
},
time: {
type: Number,
default: 0,
},
bottom: {
type: Boolean,
default: false,
},
isChange: {
type: Boolean,
default: false,
},
},
watch: {
popover(val) {
this._computedQuery(
sheep.$platform.device.windowWidth,
sheep.$platform.device.windowHeight,
);
if (val) {
if (this.tips != '' || this.time > 0) {
setTimeout(
() => {
this.popover = false;
},
this.time == 0 ? 3000 : this.time,
);
}
this.sys_layer = this.sys_layer + 100;
} else {
this.sys_layer = this.sys_layer - 100;
}
this.$emit('update:show', val);
},
show(val) {
this.popover = val;
},
},
mounted() {
this.$nextTick(() => {
this._computedQuery(
sheep.$platform.device.windowWidth,
sheep.$platform.device.windowHeight,
);
// #ifdef H5
uni.onWindowResize((res) => {
this._computedQuery(res.size.windowWidth, res.size.windowHeight);
});
// #endif
});
},
methods: {
_onHide() {
this.popover = false;
},
_computedQuery(w, h) {
uni
.createSelectorQuery()
.in(this)
.select('#popover-button-' + this.elId)
.boundingClientRect((button) => {
if (button != null) {
this.button = button;
} else {
console.log('popover-button-' + this.elId + ' data error');
}
})
.select('#popover-content-' + this.elId)
.boundingClientRect((content) => {
if (content != null) {
this.content = content;
let button = this.button;
//contentStyle
let contentStyle = '';
let arrowStyle = '';
this.BoxStyle = `width:${w}px; left:-${button.left}px;z-index: ${
this.index + this.sys_layer + 102
}`;
// 判断气泡在上面还是下面
if (button.bottom < h / 2 || this.bottom) {
// '下';
contentStyle = contentStyle + `top:10px;`;
arrowStyle = arrowStyle + `top:${-5}px;`;
} else {
// '上';
contentStyle = contentStyle + `bottom:${button.height + 10}px;`;
arrowStyle = arrowStyle + `bottom:${-5}px;`;
}
// 判断气泡箭头在左中右
let btnCenter = button.right - button.width / 2;
let contentCenter = content.right - content.width / 2;
if (
(btnCenter < w / 3 && content.width > btnCenter) ||
(content.width > w / 2 && btnCenter < w / 2)
) {
// '左';
contentStyle = contentStyle + `left:10px;`;
arrowStyle = arrowStyle + `left:${btnCenter - 17}px;`;
} else if (
(btnCenter > (w / 6) * 4 && content.width > w - btnCenter) ||
(content.width > w / 2 && btnCenter > w / 2)
) {
// '右';
contentStyle = contentStyle + `right:10px;`;
arrowStyle = arrowStyle + `right:${w - btnCenter - 17}px;`;
} else {
// '中';
contentStyle =
contentStyle + `left:${button.left - content.width / 2 + button.width / 2}px;`;
arrowStyle = arrowStyle + `left:0px;right:0px;margin:auto;`;
}
this.arrowStyle = arrowStyle + `z-index:${this.index + this.sys_layer + 1};`;
this.contentStyle = contentStyle + `z-index:${this.index + this.sys_layer + 2};`;
} else {
console.log('popover-content-' + this.elId + ' data error');
}
})
.exec();
},
popoverClick() {
if (this.isChange) {
return false;
}
if (this.tips == '') {
this.popover = !this.popover;
} else {
this.popover = true;
}
},
mouseover() {
if (this.hover && (this.tips != '' || this.content.height != 0)) {
this.popover = true;
}
},
mouseleave() {
if (this.hover) {
this.popover = false;
}
},
},
};
</script>
<style lang="scss">
.ui-popover {
position: relative;
.ui-popover-button {
position: relative;
}
.ui-popover-box {
position: absolute;
.ui-popover-content-box {
position: absolute;
.ui-popover-content {
position: relative;
}
.ui-popover-arrow {
position: absolute;
height: 15px;
width: 15px;
border-radius: 2px;
transform: rotate(45deg);
}
&::after {
content: '';
width: 100%;
height: 110%;
position: absolute;
background-color: #000000;
top: 5%;
left: 0;
filter: blur(15px);
opacity: 0.15;
}
}
}
.ui-popover-mask {
position: fixed;
width: 100%;
height: 100%;
top: 0;
left: 0;
}
&.show {
.ui-popover-button {
}
.ui-popover-content-box {
opacity: 1;
pointer-events: auto;
}
.ui-popover-arrow {
display: block;
}
.ui-popover-mask {
display: block;
}
}
&.hide {
.ui-popover-button {
}
.ui-popover-content-box {
opacity: 0;
pointer-events: none;
}
.ui-popover-arrow {
display: none;
}
.ui-popover-mask {
display: none;
}
}
}
</style>