Browse Source

fix(popover): 位置计算逻辑优化 (#710)

liqiong-lab 4 years ago
parent
commit
142a921999

+ 0 - 26
src/packages/__VUE/popover/index.scss

@@ -7,7 +7,6 @@
     background: $popover-white-background-color;
     opacity: 0;
     position: fixed;
-    top: 49px;
     width: 100%;
     height: 1000px;
     z-index: 10;
@@ -26,11 +25,8 @@
     font-weight: normal;
     color: $popover-primary-text-color;
     position: absolute;
-    top: 49px;
     .popoverArrow {
       position: absolute;
-      left: 10px;
-      top: -18px;
       width: 0;
       height: 0;
       border-left: 8px solid transparent;
@@ -59,11 +55,8 @@
     }
   }
   .popoverContent--top {
-    top: -126px;
     .popoverArrow--top {
       position: absolute;
-      left: 10px;
-      bottom: -15px;
       top: auto;
       border-left: 8px solid transparent;
       border-right: 8px solid transparent;
@@ -72,12 +65,8 @@
     }
   }
   .popoverContent--left {
-    top: -30px;
-    left: -90px;
     .popoverArrow--left {
       position: absolute;
-      right: -13px;
-      top: 49px;
       border-left: 10px solid $popover-white-background-color;
       border-right: 10px solid transparent;
       border-top: 8px solid transparent;
@@ -85,12 +74,8 @@
     }
   }
   .popoverContent--right {
-    top: -30px;
-    right: -90px;
     .popoverArrow--right {
       position: absolute;
-      left: -10px;
-      top: 49px;
       border-left: 10px solid transparent;
       border-right: 10px solid $popover-white-background-color;
       border-top: 8px solid transparent;
@@ -118,11 +103,8 @@
     }
   }
   .popoverContent--top {
-    top: -126px;
     .popoverArrow--top {
       position: absolute;
-      left: 10px;
-      bottom: -20px;
       top: auto;
       border-left: 8px solid transparent;
       border-right: 8px solid transparent;
@@ -131,12 +113,8 @@
     }
   }
   .popoverContent--left {
-    top: -30px;
-    left: -90px;
     .popoverArrow--left {
       position: absolute;
-      left: 75px;
-      top: 49px;
       border-left: 10px solid $popover-dark-background-color;
       border-right: 10px solid transparent;
       border-top: 8px solid transparent;
@@ -144,12 +122,8 @@
     }
   }
   .popoverContent--right {
-    top: -30px;
-    right: -90px;
     .popoverArrow--right {
       position: absolute;
-      left: -19px;
-      top: 49px;
       border-left: 10px solid transparent;
       border-right: 10px solid $popover-dark-background-color;
       border-top: 8px solid transparent;

+ 68 - 10
src/packages/__VUE/popover/index.taro.vue

@@ -1,11 +1,10 @@
 <template>
   <view @click="openPopover" :class="classes">
-    <slot name="reference"></slot>
-
+    <div ref="reference" :id="'reference-' + refRandomId"> <slot name="reference"></slot></div>
     <template v-if="showPopup">
       <view class="more-background" @click="closePopover"> </view>
-      <view :class="popoverContent">
-        <view :class="popoverArrow"> </view>
+      <view :class="popoverContent" :style="getStyle">
+        <view :class="popoverArrow" :style="getArrowStyle"> </view>
 
         <slot name="content"></slot>
 
@@ -13,7 +12,7 @@
           v-for="item in list"
           :key="item.name"
           :class="{ 'title-item': true, disabled: item.disabled }"
-          @click="chooseItem"
+          @click="chooseItem(e, item)"
         >
           <slot v-if="item.icon"> <nut-icon class="item-img" :name="item.icon"></nut-icon></slot>
           <view class="title-name">{{ item.name }}</view>
@@ -23,12 +22,13 @@
   </view>
 </template>
 <script lang="ts">
-import { onMounted, computed, watch, ref, PropType, toRefs } from 'vue';
+import { onMounted, computed, watch, ref, PropType, toRefs, reactive, CSSProperties } from 'vue';
 import { createComponent } from '../../utils/create';
 const { componentName, create } = createComponent('popover');
 import Popup, { popupProps } from '../popup/index.vue';
 import Button from '../button/index.vue';
-
+import { useTaroRect } from '../../utils/useTaroRect';
+import Taro from '@tarojs/taro';
 export type PopoverTheme = 'light' | 'dark';
 
 export type PopoverLocation = 'bottom' | 'top' | 'left' | 'right';
@@ -58,6 +58,11 @@ export default create({
   },
   emits: ['update', 'update:visible', 'close', 'choose', 'openPopover'],
   setup(props, { emit }) {
+    const reference = ref<HTMLElement>();
+    const state = reactive({
+      elWidth: 0,
+      elHeight: 0
+    });
     const showPopup = ref(props.visible);
 
     const { theme, location } = toRefs(props);
@@ -86,7 +91,53 @@ export default create({
       };
     });
 
-    onMounted(() => {});
+    const getReference = async () => {
+      const refe = await useTaroRect(reference, Taro);
+      state.elWidth = refe.width;
+      state.elHeight = refe.height;
+    };
+
+    const getStyle = computed(() => {
+      const style: CSSProperties = {};
+      if (location.value == 'top') {
+        style.bottom = state.elHeight + 10 + 'px';
+      } else if (location.value == 'right') {
+        style.top = 0 + 'px';
+        style.right = -state.elWidth + 'px';
+      } else if (location.value == 'left') {
+        style.top = 0 + 'px';
+        style.left = -state.elWidth + 'px';
+      } else {
+        style.top = state.elHeight + 10 + 'px';
+      }
+
+      return style;
+    });
+
+    const getArrowStyle = computed(() => {
+      const style: CSSProperties = {};
+      if (location.value == 'top') {
+        style.bottom = -20 + 'px';
+        style.left = state.elWidth / 2 + 'px';
+      } else if (location.value == 'right') {
+        style.top = 20 + 'px';
+        style.left = -20 + 'px';
+      } else if (location.value == 'left') {
+        style.top = 20 + 'px';
+        style.right = -20 + 'px';
+      } else {
+        style.left = state.elWidth / 2 + 'px';
+        style.top = -20 + 'px';
+      }
+
+      return style;
+    });
+
+    onMounted(() => {
+      setTimeout(() => {
+        getReference();
+      }, 200);
+    });
 
     watch(
       () => props.visible,
@@ -114,12 +165,14 @@ export default create({
       emit('update:visible', false);
     };
 
-    const chooseItem = (event: Event) => {
+    const chooseItem = (event: Event, item: any) => {
       event.stopPropagation();
       event.preventDefault();
       emit('choose');
     };
 
+    const refRandomId = Math.random().toString(36).slice(-8);
+
     return {
       classes,
       showPopup,
@@ -127,7 +180,12 @@ export default create({
       popoverContent,
       popoverArrow,
       closePopover,
-      chooseItem
+      chooseItem,
+      getReference,
+      reference,
+      getStyle,
+      getArrowStyle,
+      refRandomId
     };
   }
 });

+ 61 - 7
src/packages/__VUE/popover/index.vue

@@ -1,11 +1,10 @@
 <template>
   <view @click="openPopover" :class="classes">
-    <slot name="reference"></slot>
-
+    <div ref="reference"> <slot name="reference"></slot></div>
     <template v-if="showPopup">
       <view class="more-background" @click="closePopover"> </view>
-      <view :class="popoverContent">
-        <view :class="popoverArrow"> </view>
+      <view :class="popoverContent" :style="getStyle">
+        <view :class="popoverArrow" :style="getArrowStyle"> </view>
 
         <slot name="content"></slot>
 
@@ -23,7 +22,7 @@
   </view>
 </template>
 <script lang="ts">
-import { onMounted, computed, watch, ref, PropType, toRefs } from 'vue';
+import { onMounted, computed, watch, ref, PropType, toRefs, reactive, CSSProperties } from 'vue';
 import { createComponent } from '../../utils/create';
 const { componentName, create } = createComponent('popover');
 import Popup, { popupProps } from '../popup/index.vue';
@@ -58,6 +57,11 @@ export default create({
   },
   emits: ['update', 'update:visible', 'close', 'choose', 'openPopover'],
   setup(props, { emit }) {
+    const reference = ref();
+    const state = reactive({
+      elWidth: 0,
+      elHeight: 0
+    });
     const showPopup = ref(props.visible);
 
     const { theme, location } = toRefs(props);
@@ -86,7 +90,53 @@ export default create({
       };
     });
 
-    onMounted(() => {});
+    function getReference() {
+      const domElem = document.documentElement;
+      state.elWidth = reference.value.offsetWidth;
+      state.elHeight = reference.value.offsetHeight;
+    }
+
+    const getStyle = computed(() => {
+      const style: CSSProperties = {};
+      if (location.value == 'top') {
+        style.bottom = state.elHeight + 20 + 'px';
+        style.left = 0 + 'px';
+      } else if (location.value == 'right') {
+        style.top = 0 + 'px';
+        style.right = -state.elWidth + 'px';
+      } else if (location.value == 'left') {
+        style.top = 0 + 'px';
+        style.left = -state.elWidth + 'px';
+      } else {
+        style.top = state.elHeight + 20 + 'px';
+        style.left = 0 + 'px';
+      }
+
+      return style;
+    });
+
+    const getArrowStyle = computed(() => {
+      const style: CSSProperties = {};
+      if (location.value == 'top') {
+        style.bottom = -20 + 'px';
+        style.left = state.elWidth / 2 + 'px';
+      } else if (location.value == 'right') {
+        style.top = 20 + 'px';
+        style.left = -20 + 'px';
+      } else if (location.value == 'left') {
+        style.top = 20 + 'px';
+        style.right = -20 + 'px';
+      } else {
+        style.left = state.elWidth / 2 + 'px';
+        style.top = -20 + 'px';
+      }
+
+      return style;
+    });
+
+    onMounted(() => {
+      getReference();
+    });
 
     watch(
       () => props.visible,
@@ -127,7 +177,11 @@ export default create({
       popoverContent,
       popoverArrow,
       closePopover,
-      chooseItem
+      chooseItem,
+      getReference,
+      reference,
+      getStyle,
+      getArrowStyle
     };
   }
 });