fix(tooltip): support adjust the tooltip position that overstep the boundary

This commit is contained in:
Sagi 2022-10-16 22:50:13 +08:00
parent 879c3c9dc2
commit 7f142a71af
5 changed files with 60 additions and 16 deletions

View File

@ -1,3 +1,4 @@
import { DomEvent } from "@vue/test-utils/dist/constants/dom-events";
import { SetupContext } from "vue"; import { SetupContext } from "vue";
import { TooltipPlacement, TooltipProps } from "../tooltip.props"; import { TooltipPlacement, TooltipProps } from "../tooltip.props";
import { RectPosition, TooltipPosition } from "./types"; import { RectPosition, TooltipPosition } from "./types";
@ -28,10 +29,15 @@ export function useAdjustPosition(props: TooltipProps, context: SetupContext) {
placementAndAlignment: TooltipPlacement, placementAndAlignment: TooltipPlacement,
originalPosition: TooltipPosition, originalPosition: TooltipPosition,
relativeElementRect: DOMRect, relativeElementRect: DOMRect,
tooltipRect: DOMRect hostRect: DOMRect,
tooltipRect: DOMRect,
tooltipContentRect: DOMRect,
arrowRect: DOMRect
): TooltipPosition { ): TooltipPosition {
let fixedLeft = originalPosition.tooltip.left; let fixedLeft = originalPosition.tooltip.left;
let fixedTop = originalPosition.tooltip.top; let fixedTop = originalPosition.tooltip.top;
let fixedArrowLeft = originalPosition.arrow.left;
let fixedArrowTop = originalPosition.arrow.top;
const placementAndAlignmentArray = placementAndAlignment.split('-'); const placementAndAlignmentArray = placementAndAlignment.split('-');
const placement = placementAndAlignmentArray[0]; const placement = placementAndAlignmentArray[0];
if (['top', 'bottom'].includes(placement)) { if (['top', 'bottom'].includes(placement)) {
@ -40,14 +46,24 @@ export function useAdjustPosition(props: TooltipProps, context: SetupContext) {
fixedLeft = overLeftBound.overBound ? fixedLeft = overLeftBound.overBound ?
overLeftBound.fixedValue : overLeftBound.fixedValue :
(overRightBound.overBound ? overRightBound.fixedValue - tooltipRect.width : originalPosition.tooltip.left); (overRightBound.overBound ? overRightBound.fixedValue - tooltipRect.width : originalPosition.tooltip.left);
fixedArrowLeft = overLeftBound.overBound ?
tooltipRect.width - ((fixedLeft + tooltipRect.width) - hostRect.right) - arrowRect.width :
(overRightBound.overBound ? hostRect.left - fixedLeft : originalPosition.arrow.left);
} }
const overTopBound = isOverstepBoundary(relativeElementRect, 'top', originalPosition.tooltip.top); const overTopBound = isOverstepBoundary(relativeElementRect, 'top', originalPosition.tooltip.top);
const overBottomBound = isOverstepBoundary(relativeElementRect, 'bottom', originalPosition.tooltip.top + tooltipRect.height); const overBottomBound = isOverstepBoundary(relativeElementRect, 'bottom', originalPosition.tooltip.top + tooltipRect.height);
fixedTop = overTopBound.overBound ? fixedTop = overTopBound.overBound ?
overTopBound.fixedValue : overTopBound.fixedValue :
(overBottomBound.overBound ? overBottomBound.fixedValue - tooltipRect.height : originalPosition.tooltip.top); (overBottomBound.overBound ? overBottomBound.fixedValue - tooltipRect.height : originalPosition.tooltip.top);
fixedArrowTop = overTopBound.overBound ?
(originalPosition.arrow.top) :
(overBottomBound.overBound ?
(
tooltipRect.height - ((fixedTop + tooltipRect.height) - hostRect.top)
) :
originalPosition.arrow.top);
const tooltip = { left: fixedLeft, top: fixedTop }; const tooltip = { left: fixedLeft, top: fixedTop };
const arrow = { left: originalPosition.arrow.left, top: originalPosition.arrow.top }; const arrow = { left: fixedArrowLeft, top: fixedArrowTop };
return { arrow, tooltip }; return { arrow, tooltip };
} }

View File

@ -14,8 +14,6 @@ export function useTooltipPosition(
tooltipContentRect: DOMRect, tooltipContentRect: DOMRect,
arrowRect: DOMRect) { arrowRect: DOMRect) {
const { scrollLeft, scrollTop } = document.documentElement;
const placementAndAlignment = ref(props.placement); const placementAndAlignment = ref(props.placement);
const { getRelativeElementBound } = useRelative(props, context); const { getRelativeElementBound } = useRelative(props, context);
@ -34,7 +32,9 @@ export function useTooltipPosition(
const relativeRect = getRelativeElementBound(); const relativeRect = getRelativeElementBound();
placementAndAlignment.value = adjustPlacement(placementAndAlignment.value, relativeRect, hostRect, tooltipRect, arrowRect); placementAndAlignment.value = adjustPlacement(placementAndAlignment.value, relativeRect, hostRect, tooltipRect, arrowRect);
const originalPosition = calculate(placementAndAlignment.value, hostRect, tooltipRect, tooltipContentRect, arrowRect); const originalPosition = calculate(placementAndAlignment.value, hostRect, tooltipRect, tooltipContentRect, arrowRect);
const position = adjustPosition(placementAndAlignment.value, originalPosition, relativeRect, tooltipRect); const position = adjustPosition(
placementAndAlignment.value, originalPosition, relativeRect, hostRect, tooltipRect, tooltipContentRect, arrowRect
);
return position; return position;
}); });

View File

@ -24,6 +24,8 @@ export default defineComponent({
return classObject; return classObject;
}); });
const { scrollLeft, scrollTop } = document.documentElement;
const shouldShowTooltipText = computed(() => isTextContext.value); const shouldShowTooltipText = computed(() => isTextContext.value);
const tooltipText = computed(() => props.content); const tooltipText = computed(() => props.content);
@ -64,9 +66,8 @@ export default defineComponent({
tooltipInnerRef.value.getBoundingClientRect(), tooltipInnerRef.value.getBoundingClientRect(),
arrowRef.value.getBoundingClientRect() arrowRef.value.getBoundingClientRect()
); );
tooltipLeftPosition.value = `${tooltipPosition.value.tooltip.left}px`; tooltipLeftPosition.value = `${tooltipPosition.value.tooltip.left + scrollLeft}px`;
tooltipRightPosition.value = `${tooltipPosition.value.tooltip.right}px`; tooltipTopPosition.value = `${tooltipPosition.value.tooltip.top + scrollTop}px`;
tooltipTopPosition.value = `${tooltipPosition.value.tooltip.top}px`;
arrowLeftPosition.value = `${tooltipPosition.value.arrow.left}px`; arrowLeftPosition.value = `${tooltipPosition.value.arrow.left}px`;
arrowTopPosition.value = `${tooltipPosition.value.arrow.top}px`; arrowTopPosition.value = `${tooltipPosition.value.arrow.top}px`;
placement.value = tooltipPlacement.value; placement.value = tooltipPlacement.value;

View File

@ -43,7 +43,7 @@ const tooltipDirective = {
element.addEventListener('mouseleave', ($event: MouseEvent) => { element.addEventListener('mouseleave', ($event: MouseEvent) => {
$event.stopPropagation(); $event.stopPropagation();
if (app) { if (app) {
// app.unmount(); app.unmount();
app = null; app = null;
} }
}); });

View File

@ -10,12 +10,39 @@ const tooltipProps = { placement: 'bottom' };
<Button v-tooltip="{ placement: 'top-right' }"> 显示提示信息 </Button> <Button v-tooltip="{ placement: 'top-right' }"> 显示提示信息 </Button>
<div id="tooltipContainer" style="width: 200px; height: 200px; background: antiquewhite; display: flex"> <div>
<Button <div id="tooltipContainer1" style="width: 250px; height: 250px; background: antiquewhite; display: inline-flex">
style="margin: auto 0 auto auto" 1
v-tooltip="{ placement: 'top-left', referenceV: '#tooltipContainer', referenceH: '#tooltipContainer' }" <Button
> style="margin: auto 0 auto auto"
显示提示信息 v-tooltip="{ placement: 'right', verticalRelative: '#tooltipContainer1', horizontalRelative: '#tooltipContainer1' }"
</Button> >
显示提示信息
</Button>
</div>
<div id="tooltipContainer2" style="width: 250px; height: 250px; background: antiquewhite; display: inline-flex">
<Button
style="margin: auto auto auto 0px"
v-tooltip="{ placement: 'left', verticalRelative: '#tooltipContainer2', horizontalRelative: '#tooltipContainer2' }"
>
显示提示信息
</Button>
</div>
<div id="tooltipContainer3" style="width: 250px; height: 250px; background: antiquewhite; display: inline-flex">
<Button
style="margin: 0px auto auto auto"
v-tooltip="{ placement: 'bottom', verticalRelative: '#tooltipContainer3', horizontalRelative: '#tooltipContainer3' }"
>
显示提示信息
</Button>
</div>
<div id="tooltipContainer4" style="width: 250px; height: 250px; background: antiquewhite; display: inline-flex">
<Button
style="margin: auto auto 0px auto"
v-tooltip="{ placement: 'top', verticalRelative: '#tooltipContainer4', horizontalRelative: '#tooltipContainer4' }"
>
显示提示信息
</Button>
</div>
</div> </div>
</template> </template>