|
@@ -0,0 +1,274 @@
|
|
|
+<template>
|
|
|
+ <view class="fs-popover">
|
|
|
+ <view class="fs-popover-refer" @click="handleClickRefer">
|
|
|
+ <slot name="refer"></slot>
|
|
|
+ </view>
|
|
|
+ <view class="fs-popover-action" v-if="actionVisible" :class="['fs-popover-' + placement]" @click="handleClose">
|
|
|
+ <view class="fs-popover-arrow"></view>
|
|
|
+ <slot>
|
|
|
+ <view class="fs-popover-action-item line1" v-for="(item, index) in actions" :key="index" @click="handleClickAction(item)">{{item.text}}</view>
|
|
|
+ </slot>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <fs-mask v-model="actionVisible" :z-index="100" bgColor="rgba(0,0,0,0)"></fs-mask>
|
|
|
+ </view>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+export default {
|
|
|
+ name:"fs-popover",
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<script setup>
|
|
|
+import { ref, onMounted } from 'vue'
|
|
|
+import utils from '@/utils/utils'
|
|
|
+
|
|
|
+const props = defineProps({
|
|
|
+ placement: {
|
|
|
+ type: String,
|
|
|
+ default: 'bottom',
|
|
|
+ validator(value) {
|
|
|
+ return ['top', 'top-start', 'top-end', 'bottom', 'bottom-start', 'bottom-end','left', 'left-start', 'left-end','right', 'right-start', 'right-end'].includes(value)
|
|
|
+ }
|
|
|
+ },
|
|
|
+ actions: Array,
|
|
|
+ bgColor: {
|
|
|
+ type: String,
|
|
|
+ default: '#fff'
|
|
|
+ },
|
|
|
+ textColor: {
|
|
|
+ type: String,
|
|
|
+ default: '#666'
|
|
|
+ },
|
|
|
+ borderColor: {
|
|
|
+ type: String,
|
|
|
+ default: '#E8EAF2'
|
|
|
+ },
|
|
|
+ zIndex: {
|
|
|
+ type: Number,
|
|
|
+ default: 99
|
|
|
+ }
|
|
|
+})
|
|
|
+const emits = defineEmits(['clickAction'])
|
|
|
+
|
|
|
+const uuid = utils.uuid()
|
|
|
+
|
|
|
+const actionVisible = ref(false)
|
|
|
+const handleClickRefer = () => {
|
|
|
+ uni.$emit('popoverClose', { uuid: uuid })
|
|
|
+ actionVisible.value = !actionVisible.value
|
|
|
+}
|
|
|
+
|
|
|
+const handleClickAction = item => {
|
|
|
+ emits('clickAction', item)
|
|
|
+}
|
|
|
+const handleClose = () => {
|
|
|
+ actionVisible.value = false
|
|
|
+}
|
|
|
+
|
|
|
+uni.$on('popoverClose', res => {
|
|
|
+ if (uuid !== res.uuid) {
|
|
|
+ handleClose()
|
|
|
+ }
|
|
|
+})
|
|
|
+
|
|
|
+defineExpose({
|
|
|
+ handleClose
|
|
|
+})
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="scss" scoped>
|
|
|
+$margin: 20rpx;
|
|
|
+$arrowOffset: 30rpx;
|
|
|
+
|
|
|
+.fs-popover{
|
|
|
+ display: inline-block;
|
|
|
+ position: relative;
|
|
|
+ z-index: v-bind(zIndex);
|
|
|
+
|
|
|
+ &-action{
|
|
|
+ position: absolute;
|
|
|
+ min-width: 260rpx;
|
|
|
+ z-index: calc(v-bind(zIndex) + 1);
|
|
|
+ background-color: v-bind(bgColor);
|
|
|
+ transition: opacity .15s,transform .15s;
|
|
|
+ border-radius: 12rpx;
|
|
|
+ padding: 0 30rpx;
|
|
|
+ color: v-bind(textColor);
|
|
|
+
|
|
|
+ &-item{
|
|
|
+ padding: 20rpx;
|
|
|
+ & + &{
|
|
|
+ border-top: 2rpx solid v-bind(borderColor);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ &-arrow{
|
|
|
+ position: absolute;
|
|
|
+ width: 0;
|
|
|
+ height: 0;
|
|
|
+ border-color: transparent;
|
|
|
+ border-style: solid;
|
|
|
+ border-width: 12rpx;
|
|
|
+ }
|
|
|
+
|
|
|
+ &-top{
|
|
|
+ left: 50%;
|
|
|
+ bottom: 100%;
|
|
|
+ transform: translateX(-50%);
|
|
|
+ margin-bottom: $margin;
|
|
|
+ .fs-popover-arrow{
|
|
|
+ border-bottom-width: 0;
|
|
|
+ border-top-color: v-bind(bgColor);
|
|
|
+ bottom: 0;
|
|
|
+ left: 50%;
|
|
|
+ transform: translate(-50%, 100%);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ &-top-start{
|
|
|
+ left: 0;
|
|
|
+ bottom: 100%;
|
|
|
+ margin-bottom: $margin;
|
|
|
+ .fs-popover-arrow{
|
|
|
+ border-bottom-width: 0;
|
|
|
+ border-top-color: v-bind(bgColor);
|
|
|
+ bottom: 0;
|
|
|
+ left: $arrowOffset;
|
|
|
+ transform: translateY(100%);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ &-top-end{
|
|
|
+ right: 0;
|
|
|
+ bottom: 100%;
|
|
|
+ margin-bottom: $margin;
|
|
|
+ .fs-popover-arrow{
|
|
|
+ border-bottom-width: 0;
|
|
|
+ border-top-color: v-bind(bgColor);
|
|
|
+ bottom: 0;
|
|
|
+ right: $arrowOffset;
|
|
|
+ transform: translateY(100%);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ &-bottom{
|
|
|
+ left: 50%;
|
|
|
+ top: 100%;
|
|
|
+ transform: translateX(-50%);
|
|
|
+ margin-top: $margin;
|
|
|
+
|
|
|
+ .fs-popover-arrow{
|
|
|
+ border-top-width: 0;
|
|
|
+ border-bottom-color: v-bind(bgColor);
|
|
|
+ top: 0;
|
|
|
+ left: 50%;
|
|
|
+ transform: translate(-50%, -100%);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ &-bottom-start{
|
|
|
+ left: 0;
|
|
|
+ top: 100%;
|
|
|
+ margin-top: $margin;
|
|
|
+
|
|
|
+ .fs-popover-arrow{
|
|
|
+ border-top-width: 0;
|
|
|
+ border-bottom-color: v-bind(bgColor);
|
|
|
+ top: 0;
|
|
|
+ left: $arrowOffset;
|
|
|
+ transform: translateY(-100%);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ &-bottom-end{
|
|
|
+ right: 0;
|
|
|
+ top: 100%;
|
|
|
+ margin-top: $margin;
|
|
|
+
|
|
|
+ .fs-popover-arrow{
|
|
|
+ border-top-width: 0;
|
|
|
+ border-bottom-color: v-bind(bgColor);
|
|
|
+ top: 0;
|
|
|
+ right: $arrowOffset;
|
|
|
+ transform: translateY(-100%);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ &-left{
|
|
|
+ left: -$margin;
|
|
|
+ top: 50%;
|
|
|
+ transform: translate(-100%, -50%);
|
|
|
+ .fs-popover-arrow{
|
|
|
+ border-right-width: 0;
|
|
|
+ border-left-color: v-bind(bgColor);
|
|
|
+ top: 50%;
|
|
|
+ right: 0;
|
|
|
+ transform: translate(100%, -50%);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ &-left-start{
|
|
|
+ left: -$margin;
|
|
|
+ top: 0;
|
|
|
+ transform: translateX(-100%);
|
|
|
+
|
|
|
+ .fs-popover-arrow{
|
|
|
+ border-right-width: 0;
|
|
|
+ border-left-color: v-bind(bgColor);
|
|
|
+ top: $arrowOffset;
|
|
|
+ right: 0;
|
|
|
+ transform: translateX(100%);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ &-left-end{
|
|
|
+ left: -$margin;
|
|
|
+ bottom: 0;
|
|
|
+ transform: translateX(-100%);
|
|
|
+
|
|
|
+ .fs-popover-arrow{
|
|
|
+ border-right-width: 0;
|
|
|
+ border-left-color: v-bind(bgColor);
|
|
|
+ bottom: $arrowOffset;
|
|
|
+ right: 0;
|
|
|
+ transform: translateX(100%);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ &-right{
|
|
|
+ left: 100%;
|
|
|
+ top: 0;
|
|
|
+ transform: translateY(-50%);
|
|
|
+ margin-left: $margin;
|
|
|
+
|
|
|
+ .fs-popover-arrow{
|
|
|
+ border-left-width: 0;
|
|
|
+ border-right-color: v-bind(bgColor);
|
|
|
+ top: 50%;
|
|
|
+ left: 0;
|
|
|
+ transform: translateX(-50%);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ &-right-start{
|
|
|
+ left: 100%;
|
|
|
+ top: 0;
|
|
|
+ margin-left: $margin;
|
|
|
+ .fs-popover-arrow{
|
|
|
+ border-left-width: 0;
|
|
|
+ border-right-color: v-bind(bgColor);
|
|
|
+ top: $arrowOffset;
|
|
|
+ left: 0;
|
|
|
+ transform: translateX(-100%);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ &-right-end{
|
|
|
+ left: 100%;
|
|
|
+ bottom: 0;
|
|
|
+ margin-left: $margin;
|
|
|
+ .fs-popover-arrow{
|
|
|
+ border-left-width: 0;
|
|
|
+ border-right-color: v-bind(bgColor);
|
|
|
+ left: 0;
|
|
|
+ bottom: $arrowOffset;
|
|
|
+ transform: translateX(-100%);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|