lilishop-uniapp/components/popups/popups.vue

344 lines
8.4 KiB
Vue

<template>
<view class="shadow" :class="!show?'':'shadow-show'" :style="{backgroundColor:show?maskBg:'rgba(0,0,0,0)'}" @tap="tapMask">
<view class="popups" :class="[theme]" :style="{top: popupsTop ,left: popupsLeft,flexDirection:direction}">
<text :class="dynPlace" :style="{width:'0px',height:'0px'}" v-if="triangle"></text>
<view v-for="(item,index) in popData" :key="index" @tap.stop="tapItem(item)" class="itemChild view" :class="[direction=='row'?'solid-right':'solid-bottom',item.disabled?'disabledColor':'']">
<u-icon size="35" :name="item.icon" v-if="item.icon"></u-icon><span class="title">{{item.title}}</span>
</view>
<slot></slot>
</view>
</view>
</template>
<script>
export default {
props: {
maskBg: {
type: String,
default: "rgba(0,0,0,0)",
},
placement: {
type: String,
default: "default", //default top-start top-end bottom-start bottom-end
},
direction: {
type: String,
default: "column", //column row
},
x: {
type: Number,
default: 0,
},
y: {
type: Number,
default: 0,
},
value: {
type: Boolean,
default: false,
},
popData: {
type: Array,
default: () => [],
},
theme: {
type: String,
default: "light", //light dark
},
dynamic: {
type: Boolean,
default: false,
},
gap: {
type: Number,
default: 20,
},
triangle: {
type: Boolean,
default: true,
},
},
data() {
return {
popupsTop: "0rpx",
popupsLeft: "0rpx",
show: false,
dynPlace: "",
};
},
mounted() {
this.popupsPosition();
},
methods: {
tapMask() {
this.$emit("input", !this.value);
},
tapItem(item) {
if (item.disabled) return;
this.$emit("tapPopup", item);
this.$emit("input", !this.value);
},
getStatusBar() {
let promise = new Promise((resolve, reject) => {
uni.getSystemInfo({
success: function (e) {
let customBar;
// #ifdef H5
customBar = e.statusBarHeight + e.windowTop;
// #endif
resolve(customBar);
},
});
});
return promise;
},
async popupsPosition() {
let statusBar = await this.getStatusBar();
let promise = new Promise((resolve, reject) => {
let popupsDom = uni.createSelectorQuery().in(this).select(".popups");
popupsDom
.fields(
{
size: true,
},
(data) => {
let width = data.width;
let height = data.height;
let y = this.dynamic
? this.dynamicGetY(this.y, this.gap)
: this.transformRpx(this.y);
let x = this.dynamic
? this.dynamicGetX(this.x, this.gap)
: this.transformRpx(this.x);
// #ifdef H5
y = this.dynamic
? this.y + statusBar
: this.transformRpx(this.y + statusBar);
// #endif
this.dynPlace =
this.placement == "default"
? this.getPlacement(x, y)
: this.placement;
switch (this.dynPlace) {
case "top-start":
this.popupsTop = `${y + 9}rpx`;
this.popupsLeft = `${x - 15}rpx`;
break;
case "top-end":
this.popupsTop = `${y + 9}rpx`;
this.popupsLeft = `${x + 15 - width}rpx`;
break;
case "bottom-start":
this.popupsTop = `${y - 18 - height}rpx`;
this.popupsLeft = `${x - 15}rpx`;
break;
case "bottom-end":
this.popupsTop = `${y - 9 - height}rpx`;
this.popupsLeft = `${x + 15 - width}rpx`;
break;
}
resolve();
}
)
.exec();
});
return promise;
},
getPlacement(x, y) {
let width = uni.getSystemInfoSync().windowWidth;
let height = uni.getSystemInfoSync().windowHeight;
if (x > width / 2 && y > height / 2) {
return "bottom-end";
} else if (x < width / 2 && y < height / 2) {
return "top-start";
} else if (x > width / 2 && y < height / 2) {
return "top-end";
} else if (x < width / 2 && y > height / 2) {
return "bottom-start";
} else if (x > width / 2) {
return "top-end";
} else {
return "top-start";
}
},
dynamicGetY(y, gap) {
let height = uni.getSystemInfoSync().windowHeight;
y = y < gap ? gap : y;
y = height - y < gap ? height - gap : y;
return y;
},
dynamicGetX(x, gap) {
let width = uni.getSystemInfoSync().windowWidth;
x = x < gap ? gap : x;
x = width - x < gap ? width - gap : x;
return x;
},
transformRpx(params) {
return (params * uni.getSystemInfoSync().screenWidth) / 375;
},
},
watch: {
value: {
immediate: true,
handler: async function (newVal, oldVal) {
if (newVal) await this.popupsPosition();
this.show = newVal;
},
},
placement: {
immediate: true,
handler(newVal, oldVal) {
this.dynPlace = newVal;
},
},
},
};
</script>
<style lang="scss" scoped>
.title {
margin-left: 20rpx;
}
.shadow {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
height: 100%;
z-index: 9999;
transition: background 0.3s ease-in-out;
visibility: hidden;
&.shadow-show {
visibility: visible;
}
}
.popups {
position: absolute;
padding: 20rpx;
border-radius: 5px;
display: flex;
.view {
display: flex;
align-items: center;
padding: 15rpx 10rpx;
font-size: 25rpx;
}
.image {
display: inline-block;
vertical-align: middle;
width: 40rpx;
height: 40rpx;
margin-right: 20rpx;
}
}
.dark {
background-color: #4c4c4c;
color: #fff;
.top-start:after {
content: "";
position: absolute;
top: -18rpx;
left: 10rpx;
border-width: 0 20rpx 20rpx;
border-style: solid;
border-color: transparent transparent #4c4c4c;
}
.top-end:after {
content: "";
position: absolute;
top: -18rpx;
right: 10rpx;
border-width: 0 20rpx 20rpx;
border-style: solid;
border-color: transparent transparent #4c4c4c;
}
.bottom-start:after {
content: "";
position: absolute;
bottom: -18rpx;
left: 10rpx;
border-width: 20rpx 20rpx 0;
border-style: solid;
border-color: #4c4c4c transparent transparent;
}
.bottom-end:after {
content: "";
position: absolute;
bottom: -18rpx;
right: 10rpx;
border-width: 20rpx 20rpx 0;
border-style: solid;
border-color: #4c4c4c transparent transparent;
}
.disabledColor {
color: #c5c8ce;
}
}
.light {
color: #515a6e;
box-shadow: 0upx 0upx 30upx rgba(0, 0, 0, 0.2);
background: #fff;
.top-start:after {
content: "";
position: absolute;
top: -18rpx;
left: 10rpx;
border-width: 0 20rpx 20rpx;
border-style: solid;
border-color: transparent transparent #fff;
}
.top-end:after {
content: "";
position: absolute;
top: -18rpx;
right: 10rpx;
border-width: 0 20rpx 20rpx;
border-style: solid;
border-color: transparent transparent #fff;
}
.bottom-start:after {
content: "";
position: absolute;
bottom: -18rpx;
left: 10rpx;
border-width: 20rpx 20rpx 0;
border-style: solid;
border-color: #fff transparent transparent;
}
.bottom-end:after {
content: "";
position: absolute;
bottom: -18rpx;
right: 10rpx;
border-width: 20rpx 20rpx 0;
border-style: solid;
border-color: #fff transparent transparent;
}
.disabledColor {
color: #c5c8ce;
}
}
.solid-bottom {
border-bottom: 1px solid #f3f5f7;
}
.solid-right {
border-right: 1px solid #ccc;
}
.popups .itemChild:last-child {
border: none;
}
</style>