feature(tooltip): add use-tooltip-position
This commit is contained in:
parent
025ca668dc
commit
465a7e1801
|
@ -0,0 +1,190 @@
|
|||
import { computed, SetupContext } from "vue";
|
||||
import { TooltipPlacement, TooltipProps } from "../tooltip.props";
|
||||
|
||||
export function useTooltipPosition(props: TooltipProps, context: SetupContext) {
|
||||
|
||||
const space = 2;
|
||||
|
||||
const tooltipPlacement = computed(() => {
|
||||
return props.placement;
|
||||
});
|
||||
|
||||
function calculateTooltipTopPositoin(placement: TooltipPlacement, hostBound: DOMRect, tooltipBound: DOMRect, arrowBound: DOMRect) {
|
||||
let offsetY = 0;
|
||||
const verticalAlignment = placement.indexOf('bottom') > -1 ? 'bottom' : (placement.indexOf('top') > -1 ? 'top' : 'middle');
|
||||
const originalPositionY = verticalAlignment === 'bottom' ? hostBound.bottom : hostBound.top;
|
||||
|
||||
if (['top', 'top-left', 'top-right'].includes(placement)) {
|
||||
offsetY = 0 - tooltipBound.height - space;
|
||||
} else if (['left', 'right'].includes(placement)) {
|
||||
offsetY = (hostBound.height - tooltipBound.height) / 2;
|
||||
} else if (['bottom', 'bottom-left', 'bottom-right'].includes(placement)) {
|
||||
offsetY = arrowBound.height + 2;
|
||||
} else if (['right-bottom', 'left-bottom'].includes(placement)) {
|
||||
offsetY = 0 - tooltipBound.height;
|
||||
} else if (['left-top', 'right-top'].includes(placement)) {
|
||||
offsetY = 0;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return originalPositionY + offsetY;
|
||||
}
|
||||
|
||||
function calculateTooltipLeftPosition(placement: TooltipPlacement, hostBound: DOMRect, tooltipBound: DOMRect, arrowBound: DOMRect) {
|
||||
|
||||
let offsetX = 0;
|
||||
const horizontalAlignment = placement.indexOf('right') > -1 ? 'right' : (placement.indexOf('left') > -1 ? 'left' : 'center');
|
||||
const originalPositionX = horizontalAlignment === 'right' ? hostBound.right : hostBound.left;
|
||||
|
||||
if (['left', 'left-top', 'left-bottom'].includes(placement)) {
|
||||
offsetX = 0 - tooltipBound.width - space;
|
||||
} else if (['top', 'bottom'].includes(placement)) {
|
||||
offsetX = (hostBound.width - tooltipBound.width) / 2;
|
||||
} else if (['right', 'right-top', 'right-bottom'].includes(placement)) {
|
||||
offsetX = space;
|
||||
} else if (['top-right', 'bottom-right'].includes(placement)) {
|
||||
offsetX = 0 - tooltipBound.width;
|
||||
} else if (['top-left', 'bottom-left'].includes(placement)) {
|
||||
offsetX = 0;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return originalPositionX + offsetX;
|
||||
}
|
||||
|
||||
function calculateTooltipRightPosition(placement: TooltipPlacement, hostBound: DOMRect, tooltipBound: DOMRect, arrowBound: DOMRect) {
|
||||
let offsetX = 0;
|
||||
const horizontalAlignment = placement.indexOf('right') > -1 ? 'right' : (placement.indexOf('left') > -1 ? 'left' : 'center');
|
||||
const originalPositionX = horizontalAlignment === 'right' ? hostBound.right : hostBound.left;
|
||||
|
||||
if (['top', 'bottom'].includes(placement)) {
|
||||
offsetX = (hostBound.width - tooltipBound.width) / 2 + tooltipBound.width;
|
||||
} else if (['top-left', 'bottom-left'].includes(placement)) {
|
||||
offsetX = tooltipBound.width;
|
||||
} else if (['top-right', 'bottom-right'].includes(placement)) {
|
||||
offsetX = 0;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return originalPositionX + offsetX;
|
||||
}
|
||||
|
||||
/* 计算tooltip最新位置 */
|
||||
function calculatePosition(hostBound: DOMRect, tooltipBound: DOMRect, arrowBound: DOMRect) {
|
||||
let top = 0;
|
||||
let left = 0;
|
||||
let right = 0;
|
||||
|
||||
switch (this.rectifyPlacement) {
|
||||
case 'top':
|
||||
top = hostPosition.top - tooltipSize.height - 2;
|
||||
left = hostPosition.left + (hostPosition.width - tooltipSize.width) / 2;
|
||||
right = left + tooltipSize.width;
|
||||
break;
|
||||
case 'left':
|
||||
top = hostPosition.top + (hostPosition.height - tooltipSize.height) / 2;
|
||||
left = hostPosition.left - tooltipSize.width - 2;
|
||||
break;
|
||||
case 'right':
|
||||
top = hostPosition.top + (hostPosition.height - tooltipSize.height) / 2;
|
||||
left = hostPosition.right + 2;
|
||||
break;
|
||||
case 'bottom':
|
||||
top = hostPosition.bottom + arrowSize.height + 2;
|
||||
left = hostPosition.left + (hostPosition.width - tooltipSize.width) / 2;
|
||||
right = left + tooltipSize.width;
|
||||
break;
|
||||
case 'top-left':
|
||||
top = hostPosition.top - tooltipSize.height - 2;
|
||||
left = hostPosition.left;
|
||||
right = left + tooltipSize.width;
|
||||
break;
|
||||
case 'top-right':
|
||||
top = hostPosition.top - tooltipSize.height - 2;
|
||||
left = hostPosition.right - tooltipSize.width;
|
||||
right = hostPosition.right;
|
||||
break;
|
||||
case 'right-top':
|
||||
top = hostPosition.top;
|
||||
left = hostPosition.right + 2;
|
||||
this.arrowNode.nativeElement.style.top = '10%';
|
||||
break;
|
||||
case 'right-bottom':
|
||||
top = hostPosition.bottom - tooltipSize.height;
|
||||
left = hostPosition.right + 2;
|
||||
this.arrowNode.nativeElement.style.bottom = '10%';
|
||||
break;
|
||||
case 'bottom-left':
|
||||
top = hostPosition.bottom + arrowSize.height + 2;
|
||||
left = hostPosition.left;
|
||||
right = left + tooltipSize.width;
|
||||
break;
|
||||
case 'bottom-right':
|
||||
top = hostPosition.bottom + arrowSize.height + 2;
|
||||
left = hostPosition.right - tooltipSize.width;
|
||||
right = hostPosition.right;
|
||||
break;
|
||||
case 'left-top':
|
||||
top = hostPosition.top;
|
||||
left = hostPosition.left - tooltipSize.width - 2;
|
||||
this.arrowNode.nativeElement.style.top = '10%';
|
||||
break;
|
||||
case 'left-bottom':
|
||||
top = hostPosition.bottom - tooltipSize.height;
|
||||
left = hostPosition.left - tooltipSize.width - 2;
|
||||
this.arrowNode.nativeElement.style.bottom = '10%';
|
||||
}
|
||||
let overResult;
|
||||
let arrowLeft = 0;
|
||||
let arrowTop = 0
|
||||
switch (this.rectifyPlacement) {
|
||||
case 'top':
|
||||
case 'top-left':
|
||||
case 'top-right':
|
||||
case 'bottom':
|
||||
case 'bottom-left':
|
||||
case 'bottom-right':
|
||||
overResult = this.isOverBounding('left', left);
|
||||
if (overResult.isOver) {
|
||||
left = overResult.newValue;
|
||||
} else {
|
||||
overResult = this.isOverBounding('right', right);
|
||||
if (overResult.isOver) {
|
||||
left = overResult.newValue - tooltipSize.width;
|
||||
}
|
||||
}
|
||||
arrowLeft = left - hostPosition.left - hostPosition.width * 0.5 + arrowSize.width * 0.5;
|
||||
if (this.rectifyPlacement.indexOf('-left') > 0) {
|
||||
arrowLeft += hostPosition.width * 0.4;
|
||||
} else if (this.rectifyPlacement.indexOf('-right') > 0) {
|
||||
arrowLeft -= hostPosition.width * 0.4;
|
||||
}
|
||||
this.arrowNode.nativeElement.style.left = Math.abs(arrowLeft) + 'px';
|
||||
break;
|
||||
default:
|
||||
overResult = this.isOverBounding('top', top);
|
||||
|
||||
if (overResult.isOver) {
|
||||
top = overResult.newValue;
|
||||
} else {
|
||||
overResult = this.isOverBounding('bottom', bottom);
|
||||
if (overResult.isOver) {
|
||||
top = overResult.newValue - tooltipSize.height;
|
||||
}
|
||||
}
|
||||
arrowTop = top - hostPosition.top - hostPosition.height * 0.5 + arrowSize.height * 0.5;;
|
||||
if (this.rectifyPlacement.indexOf('-top') > 0) {
|
||||
arrowTop += hostPosition.height * 0.4;
|
||||
} else if (this.rectifyPlacement.indexOf('-bottom') > 0) {
|
||||
arrowTop -= hostPosition.height * 0.4;
|
||||
}
|
||||
this.arrowNode.nativeElement.style.top = Math.abs(arrowTop) + 'px';
|
||||
}
|
||||
this.tooltipNode.nativeElement.style.top = top + 'px';
|
||||
this.tooltipNode.nativeElement.style.left = left + 'px';
|
||||
|
||||
}
|
||||
}
|
|
@ -10,10 +10,15 @@ export default defineComponent({
|
|||
setup(props: TooltipProps, context: SetupContext) {
|
||||
const isTextContext = ref(true);
|
||||
|
||||
const tooltipClass = computed(() => ({
|
||||
tooltip: true,
|
||||
show: true
|
||||
}));
|
||||
const tooltipClass = computed(() => {
|
||||
const classObject = {
|
||||
tooltip: true,
|
||||
show: true
|
||||
} as any;
|
||||
const tooltipClassName = `bs-tooltip-${props.position}`;
|
||||
classObject[tooltipClassName] = true;
|
||||
return classObject;
|
||||
});
|
||||
|
||||
const shouldShowTooltipText = computed(() => isTextContext.value);
|
||||
|
||||
|
@ -21,7 +26,7 @@ export default defineComponent({
|
|||
|
||||
return () => {
|
||||
return (
|
||||
<div class={tooltipClass}>
|
||||
<div class={tooltipClass.value}>
|
||||
<div class="arrow"></div>
|
||||
<div class="tooltip-inner">
|
||||
<div class="tooltip-tmpl">
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { ExtractPropTypes, PropType } from 'vue';
|
||||
|
||||
export type TooltipPosition =
|
||||
export type TooltipPlacement =
|
||||
| 'top'
|
||||
| 'top-left'
|
||||
| 'top-right'
|
||||
|
@ -18,7 +18,7 @@ export const tooltipProps = {
|
|||
content: { type: String },
|
||||
width: { type: Number },
|
||||
customClass: { type: String },
|
||||
position: { type: String as PropType<TooltipPosition>, default: 'top' },
|
||||
placement: { type: String as PropType<TooltipPlacement>, default: 'top' },
|
||||
referenceBoundingRect: { type: Object, default: {} }
|
||||
};
|
||||
export type TooltipProps = ExtractPropTypes<typeof tooltipProps>;
|
||||
|
|
Loading…
Reference in New Issue