🐛(component): [dropdown]修复 alignPoint
This commit is contained in:
parent
d6b406ed02
commit
24b19fa47b
@ -6,7 +6,7 @@ export default {
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import "./index.less";
|
import "./index.less";
|
||||||
import { ComputedRef, CSSProperties, inject, reactive, Ref } from "vue";
|
import { ComputedRef, CSSProperties, inject, reactive, Ref, toRefs } from "vue";
|
||||||
import {
|
import {
|
||||||
computed,
|
computed,
|
||||||
nextTick,
|
nextTick,
|
||||||
@ -19,7 +19,6 @@ import {
|
|||||||
} from "vue";
|
} from "vue";
|
||||||
import {
|
import {
|
||||||
onClickOutside,
|
onClickOutside,
|
||||||
useMouse,
|
|
||||||
useResizeObserver,
|
useResizeObserver,
|
||||||
useThrottleFn,
|
useThrottleFn,
|
||||||
useWindowSize,
|
useWindowSize,
|
||||||
@ -48,10 +47,10 @@ export interface LayDropdownProps {
|
|||||||
blurToClose?: boolean;
|
blurToClose?: boolean;
|
||||||
clickOutsideToClose?: boolean;
|
clickOutsideToClose?: boolean;
|
||||||
contentOffset?: number;
|
contentOffset?: number;
|
||||||
// 以下暂不开放
|
|
||||||
mouseEnterDelay?: number;
|
mouseEnterDelay?: number;
|
||||||
mouseLeaveDelay?: number;
|
mouseLeaveDelay?: number;
|
||||||
focusDelay?: number;
|
focusDelay?: number;
|
||||||
|
// 未完善,暂不开放
|
||||||
alignPoint?: boolean;
|
alignPoint?: boolean;
|
||||||
popupContainer?: string | undefined;
|
popupContainer?: string | undefined;
|
||||||
}
|
}
|
||||||
@ -86,7 +85,11 @@ const dropdownRef = shallowRef<HTMLElement | undefined>();
|
|||||||
const contentRef = shallowRef<HTMLElement | undefined>();
|
const contentRef = shallowRef<HTMLElement | undefined>();
|
||||||
const contentStyle = ref<CSSProperties>({});
|
const contentStyle = ref<CSSProperties>({});
|
||||||
const { width: windowWidth, height: windowHeight } = useWindowSize();
|
const { width: windowWidth, height: windowHeight } = useWindowSize();
|
||||||
const { x: mouseLeft, y: mouseTop } = useMouse();
|
const mousePosition = reactive({
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
});
|
||||||
|
const { x: mouseLeft, y: mouseTop } = toRefs(mousePosition);
|
||||||
const openState = ref(false);
|
const openState = ref(false);
|
||||||
|
|
||||||
const containerRef = computed(() =>
|
const containerRef = computed(() =>
|
||||||
@ -169,19 +172,32 @@ const getElementScrollRect = (element: HTMLElement, containerRect: DOMRect) => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getTriggerRect = () => {
|
||||||
|
return {
|
||||||
|
top: mouseTop.value,
|
||||||
|
bottom: mouseTop.value,
|
||||||
|
left: mouseLeft.value,
|
||||||
|
right: mouseLeft.value,
|
||||||
|
scrollTop: mouseTop.value,
|
||||||
|
scrollBottom: mouseTop.value,
|
||||||
|
scrollLeft: mouseLeft.value,
|
||||||
|
scrollRight: mouseLeft.value,
|
||||||
|
width: 0,
|
||||||
|
height: 0,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
const updateContentStyle = () => {
|
const updateContentStyle = () => {
|
||||||
if (!containerRef.value || !dropdownRef.value || !contentRef.value) {
|
if (!containerRef.value || !dropdownRef.value || !contentRef.value) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const containerRect = containerRef.value.getBoundingClientRect();
|
const containerRect = containerRef.value.getBoundingClientRect();
|
||||||
const triggerRect = getElementScrollRect(dropdownRef.value, containerRect);
|
const triggerRect = props.alignPoint
|
||||||
|
? getTriggerRect()
|
||||||
|
: getElementScrollRect(dropdownRef.value, containerRect);
|
||||||
const contentRect = getElementScrollRect(contentRef.value, containerRect);
|
const contentRect = getElementScrollRect(contentRef.value, containerRect);
|
||||||
const { style } = getContentStyle(
|
const { style } = getContentStyle(props.placement, triggerRect, contentRect);
|
||||||
props.placement,
|
|
||||||
triggerRect,
|
|
||||||
contentRect,
|
|
||||||
props.alignPoint
|
|
||||||
);
|
|
||||||
|
|
||||||
if (props.autoFitMinWidth) {
|
if (props.autoFitMinWidth) {
|
||||||
style.minWidth = `${triggerRect.width}px`;
|
style.minWidth = `${triggerRect.width}px`;
|
||||||
@ -193,10 +209,9 @@ const updateContentStyle = () => {
|
|||||||
|
|
||||||
if (props.autoFitPosition) {
|
if (props.autoFitPosition) {
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
const triggerRect = getElementScrollRect(
|
const triggerRect = props.alignPoint
|
||||||
dropdownRef.value as HTMLElement,
|
? getTriggerRect()
|
||||||
containerRect
|
: getElementScrollRect(dropdownRef.value as HTMLElement, containerRect);
|
||||||
);
|
|
||||||
const contentRect = getElementScrollRect(
|
const contentRect = getElementScrollRect(
|
||||||
contentRef.value as HTMLElement,
|
contentRef.value as HTMLElement,
|
||||||
containerRect
|
containerRect
|
||||||
@ -220,23 +235,25 @@ const updateContentStyle = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const updateMousePosition = (e: MouseEvent) => {
|
||||||
|
if (props.alignPoint) {
|
||||||
|
const { pageX, pageY } = e;
|
||||||
|
mousePosition.x = pageX;
|
||||||
|
mousePosition.y = pageY;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const getContentStyle = (
|
const getContentStyle = (
|
||||||
placement: DropdownPlacement,
|
placement: DropdownPlacement,
|
||||||
triggerRect: ElementScrollRect,
|
triggerRect: ElementScrollRect,
|
||||||
contentRect: ElementScrollRect,
|
contentRect: ElementScrollRect,
|
||||||
isAlignPoint?: boolean,
|
|
||||||
{
|
{
|
||||||
customStyle = {},
|
customStyle = {},
|
||||||
}: {
|
}: {
|
||||||
customStyle?: CSSProperties;
|
customStyle?: CSSProperties;
|
||||||
} = {}
|
} = {}
|
||||||
) => {
|
) => {
|
||||||
let { top, left } = getContentOffset(
|
let { top, left } = getContentOffset(placement, triggerRect, contentRect);
|
||||||
placement,
|
|
||||||
triggerRect,
|
|
||||||
contentRect,
|
|
||||||
isAlignPoint
|
|
||||||
);
|
|
||||||
const style = {
|
const style = {
|
||||||
top: `${top}px`,
|
top: `${top}px`,
|
||||||
left: `${left}px`,
|
left: `${left}px`,
|
||||||
@ -318,15 +335,8 @@ const getFitPlacement = (
|
|||||||
const getContentOffset = (
|
const getContentOffset = (
|
||||||
placement: DropdownPlacement,
|
placement: DropdownPlacement,
|
||||||
triggerRect: ElementScrollRect,
|
triggerRect: ElementScrollRect,
|
||||||
contentRect: ElementScrollRect,
|
contentRect: ElementScrollRect
|
||||||
isAlignPoint?: boolean
|
|
||||||
) => {
|
) => {
|
||||||
if (isAlignPoint) {
|
|
||||||
return {
|
|
||||||
top: mouseTop.value - triggerRect.top,
|
|
||||||
left: mouseLeft.value - triggerRect.left,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
switch (placement) {
|
switch (placement) {
|
||||||
case "top":
|
case "top":
|
||||||
return {
|
return {
|
||||||
@ -429,11 +439,12 @@ const handleScroll = useThrottleFn(() => {
|
|||||||
}
|
}
|
||||||
}, 10);
|
}, 10);
|
||||||
|
|
||||||
const handleClick = () => {
|
const handleClick = (e: MouseEvent) => {
|
||||||
if (props.disabled || (openState.value && !props.clickToClose)) {
|
if (props.disabled || (openState.value && !props.clickToClose)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (triggerMethods.value.includes("click")) {
|
if (triggerMethods.value.includes("click")) {
|
||||||
|
updateMousePosition(e);
|
||||||
toggle();
|
toggle();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -447,6 +458,7 @@ const handleContextMenuClick = (e: MouseEvent) => {
|
|||||||
if (props.alignPoint) {
|
if (props.alignPoint) {
|
||||||
hide();
|
hide();
|
||||||
}
|
}
|
||||||
|
updateMousePosition(e);
|
||||||
toggle();
|
toggle();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -582,21 +594,6 @@ watch(
|
|||||||
{ immediate: true }
|
{ immediate: true }
|
||||||
);
|
);
|
||||||
|
|
||||||
const getTriggerRect = (isAlignPoint: boolean) => {
|
|
||||||
return isAlignPoint
|
|
||||||
? ({
|
|
||||||
top: mouseTop.value,
|
|
||||||
bottom: mouseTop.value,
|
|
||||||
left: mouseLeft.value,
|
|
||||||
right: mouseLeft.value,
|
|
||||||
width: 0,
|
|
||||||
height: 0,
|
|
||||||
x: mouseLeft.value,
|
|
||||||
y: mouseTop.value,
|
|
||||||
} as DOMRect)
|
|
||||||
: dropdownRef.value!.getBoundingClientRect();
|
|
||||||
};
|
|
||||||
|
|
||||||
provide("openState", openState);
|
provide("openState", openState);
|
||||||
|
|
||||||
defineExpose({ open, hide, toggle });
|
defineExpose({ open, hide, toggle });
|
||||||
@ -612,7 +609,7 @@ defineExpose({ open, hide, toggle });
|
|||||||
@focusout="handleFocusout()"
|
@focusout="handleFocusout()"
|
||||||
:class="{ 'layui-dropdown-up': openState }"
|
:class="{ 'layui-dropdown-up': openState }"
|
||||||
>
|
>
|
||||||
<div @click="handleClick()" @contextmenu="handleContextMenuClick">
|
<div @click="handleClick" @contextmenu="handleContextMenuClick">
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
</div>
|
</div>
|
||||||
<TeleportWrapper :to="popupContainer">
|
<TeleportWrapper :to="popupContainer">
|
||||||
|
@ -587,6 +587,9 @@ export default {
|
|||||||
| blurToClose | 是否在触发器失去焦点时关闭面板,默认 `true` |`true` `false`|
|
| blurToClose | 是否在触发器失去焦点时关闭面板,默认 `true` |`true` `false`|
|
||||||
| clickOutsideToClose| 是否点击外部关闭下拉面板,默认 `true`|`true` `false`|
|
| clickOutsideToClose| 是否点击外部关闭下拉面板,默认 `true`|`true` `false`|
|
||||||
| contentOffset | 下拉面板距离触发器的偏移距离,默认 2| -|
|
| contentOffset | 下拉面板距离触发器的偏移距离,默认 2| -|
|
||||||
|
| mouseEnterDelay | mouseEnter 事件延迟触发的时间, trigger hover 有效 | - |
|
||||||
|
| mouseLeaveDelay | mouseLeave 事件延迟触发的时间, trigger hover 有效| - |
|
||||||
|
| focusDelay| focus 事件延迟触发的时间, trigger focus 有效 | - |
|
||||||
|
|
||||||
|
|
||||||
:::
|
:::
|
||||||
|
Loading…
Reference in New Issue
Block a user