✨(dropdown): 支持渲染到 body
This commit is contained in:
parent
18edd93618
commit
7ed837fe7d
@ -3,8 +3,8 @@
|
|||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.layui-dropdown-content,
|
||||||
.layui-dropdown dl {
|
.layui-dropdown dl {
|
||||||
display: none;
|
|
||||||
position: absolute;
|
position: absolute;
|
||||||
z-index: 899;
|
z-index: 899;
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
@ -14,6 +14,7 @@
|
|||||||
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, .1);
|
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, .1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.layui-dropdown-content > .layui-dropdown-menu,
|
||||||
.layui-dropdown dl > .layui-dropdown-menu {
|
.layui-dropdown dl > .layui-dropdown-menu {
|
||||||
border-radius: var(--global-border-radius);
|
border-radius: var(--global-border-radius);
|
||||||
}
|
}
|
||||||
@ -22,16 +23,20 @@
|
|||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.layui-dropdown-content .layui-menu,
|
||||||
.layui-dropdown .layui-menu {
|
.layui-dropdown .layui-menu {
|
||||||
position: relative;
|
position: relative;
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.layui-dropdown-content .layui-menu li,
|
||||||
|
.layui-dropdown-content .layui-menu-body-title a,
|
||||||
.layui-dropdown .layui-menu li,
|
.layui-dropdown .layui-menu li,
|
||||||
.layui-dropdown .layui-menu-body-title a {
|
.layui-dropdown .layui-menu-body-title a {
|
||||||
padding: 5px 15px;
|
padding: 5px 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.layui-dropdown-content .layui-menu li,
|
||||||
.layui-dropdown .layui-menu li {
|
.layui-dropdown .layui-menu li {
|
||||||
position: relative;
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -42,10 +47,12 @@
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.layui-dropdown-content .layui-menu li:hover,
|
||||||
.layui-dropdown .layui-menu li:hover {
|
.layui-dropdown .layui-menu li:hover {
|
||||||
background-color: var(--global-neutral-color-2);
|
background-color: var(--global-neutral-color-2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.layui-dropdown-content .layui-menu-body-title,
|
||||||
.layui-dropdown .layui-menu-body-title {
|
.layui-dropdown .layui-menu-body-title {
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
@ -59,6 +66,7 @@
|
|||||||
margin-left: 15px;
|
margin-left: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.layui-dropdown-content .layui-line-horizontal,
|
||||||
.layui-dropdown .layui-line-horizontal{
|
.layui-dropdown .layui-line-horizontal{
|
||||||
margin: 0px;
|
margin: 0px;
|
||||||
border-color: #EEEEEE;
|
border-color: #EEEEEE;
|
||||||
|
@ -6,7 +6,7 @@ export default {
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import "./index.less";
|
import "./index.less";
|
||||||
import type { CSSProperties } from "vue";
|
import { CSSProperties, inject, reactive, Ref } from "vue";
|
||||||
import {
|
import {
|
||||||
computed,
|
computed,
|
||||||
nextTick,
|
nextTick,
|
||||||
@ -24,7 +24,12 @@ import {
|
|||||||
useThrottleFn,
|
useThrottleFn,
|
||||||
useWindowSize,
|
useWindowSize,
|
||||||
} from "@vueuse/core";
|
} from "@vueuse/core";
|
||||||
import type { DropdownPlacement } from "./interface";
|
import {
|
||||||
|
dropdownInjectionKey,
|
||||||
|
DropdownPlacement,
|
||||||
|
ElementScrollRect,
|
||||||
|
DropdownContext,
|
||||||
|
} from "./interface";
|
||||||
|
|
||||||
export type DropdownTrigger = "click" | "hover" | "focus" | "contextMenu";
|
export type DropdownTrigger = "click" | "hover" | "focus" | "contextMenu";
|
||||||
|
|
||||||
@ -47,6 +52,7 @@ export interface LayDropdownProps {
|
|||||||
mouseLeaveDelay?: number;
|
mouseLeaveDelay?: number;
|
||||||
focusDelay?: number;
|
focusDelay?: number;
|
||||||
alignPoint?: boolean;
|
alignPoint?: boolean;
|
||||||
|
renderToBody?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = withDefaults(defineProps<LayDropdownProps>(), {
|
const props = withDefaults(defineProps<LayDropdownProps>(), {
|
||||||
@ -67,8 +73,11 @@ const props = withDefaults(defineProps<LayDropdownProps>(), {
|
|||||||
mouseLeaveDelay: 150,
|
mouseLeaveDelay: 150,
|
||||||
focusDelay: 150,
|
focusDelay: 150,
|
||||||
alignPoint: false,
|
alignPoint: false,
|
||||||
|
renderToBody: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const childrenRefs = new Set<Ref<HTMLElement>>();
|
||||||
|
const dropdownCtx = inject<DropdownContext>(dropdownInjectionKey, undefined);
|
||||||
const dropdownRef = shallowRef<HTMLElement | undefined>();
|
const dropdownRef = shallowRef<HTMLElement | undefined>();
|
||||||
const contentRef = shallowRef<HTMLElement | undefined>();
|
const contentRef = shallowRef<HTMLElement | undefined>();
|
||||||
const contentStyle = ref<CSSProperties>({});
|
const contentStyle = ref<CSSProperties>({});
|
||||||
@ -133,12 +142,34 @@ const changeVisible = (visible: boolean, delay?: number) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const containerRef = computed(() =>
|
||||||
|
props.renderToBody ? document.body : dropdownRef.value
|
||||||
|
);
|
||||||
|
|
||||||
|
const getElementScrollRect = (element: HTMLElement, containerRect: DOMRect) => {
|
||||||
|
const rect = element.getBoundingClientRect();
|
||||||
|
|
||||||
|
return {
|
||||||
|
top: rect.top,
|
||||||
|
bottom: rect.bottom,
|
||||||
|
left: rect.left,
|
||||||
|
right: rect.right,
|
||||||
|
width: rect.width,
|
||||||
|
height: rect.height,
|
||||||
|
scrollTop: rect.top - containerRect.top,
|
||||||
|
scrollBottom: rect.bottom - containerRect.top,
|
||||||
|
scrollLeft: rect.left - containerRect.left,
|
||||||
|
scrollRight: rect.right - containerRect.left,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
const updateContentStyle = () => {
|
const updateContentStyle = () => {
|
||||||
if (!dropdownRef.value || !contentRef.value) {
|
if (!containerRef.value || !dropdownRef.value || !contentRef.value) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const triggerRect = dropdownRef.value!.getBoundingClientRect();
|
const containerRect = containerRef.value.getBoundingClientRect();
|
||||||
const contentRect = contentRef.value.getBoundingClientRect();
|
const triggerRect = getElementScrollRect(dropdownRef.value, containerRect);
|
||||||
|
const contentRect = getElementScrollRect(contentRef.value, containerRect);
|
||||||
const { style } = getContentStyle(
|
const { style } = getContentStyle(
|
||||||
props.placement,
|
props.placement,
|
||||||
triggerRect,
|
triggerRect,
|
||||||
@ -156,8 +187,14 @@ const updateContentStyle = () => {
|
|||||||
|
|
||||||
if (props.autoFitPosition) {
|
if (props.autoFitPosition) {
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
const triggerRect = dropdownRef.value!.getBoundingClientRect();
|
const triggerRect = getElementScrollRect(
|
||||||
const contentRect = contentRef.value!.getBoundingClientRect();
|
dropdownRef.value as HTMLElement,
|
||||||
|
containerRect
|
||||||
|
);
|
||||||
|
const contentRect = getElementScrollRect(
|
||||||
|
contentRef.value as HTMLElement,
|
||||||
|
containerRect
|
||||||
|
);
|
||||||
let { top, left } = style;
|
let { top, left } = style;
|
||||||
top = Number(top.toString().replace("px", ""));
|
top = Number(top.toString().replace("px", ""));
|
||||||
left = Number(left.toString().replace("px", ""));
|
left = Number(left.toString().replace("px", ""));
|
||||||
@ -179,8 +216,8 @@ const updateContentStyle = () => {
|
|||||||
|
|
||||||
const getContentStyle = (
|
const getContentStyle = (
|
||||||
placement: DropdownPlacement,
|
placement: DropdownPlacement,
|
||||||
triggerRect: DOMRect,
|
triggerRect: ElementScrollRect,
|
||||||
contentRect: DOMRect,
|
contentRect: ElementScrollRect,
|
||||||
isAlignPoint?: boolean,
|
isAlignPoint?: boolean,
|
||||||
{
|
{
|
||||||
customStyle = {},
|
customStyle = {},
|
||||||
@ -224,19 +261,19 @@ const getFitPlacement = (
|
|||||||
top: number,
|
top: number,
|
||||||
left: number,
|
left: number,
|
||||||
placement: DropdownPlacement,
|
placement: DropdownPlacement,
|
||||||
triggerRect: DOMRect,
|
triggerRect: ElementScrollRect,
|
||||||
contentRect: DOMRect
|
contentRect: ElementScrollRect
|
||||||
) => {
|
) => {
|
||||||
// FIXME 反转后仍溢出的场景
|
// FIXME 反转后仍溢出的场景
|
||||||
const position = getPosition(placement);
|
const position = getPosition(placement);
|
||||||
if (["top", "bottom"].includes(position)) {
|
if (["top", "bottom"].includes(position)) {
|
||||||
// 溢出屏幕底部
|
// 溢出屏幕底部
|
||||||
if (contentRect.bottom > windowHeight.value) {
|
if (contentRect.bottom > windowHeight.value) {
|
||||||
top = -contentRect.height - props.contentOffset;
|
top = triggerRect.scrollTop - contentRect.height - props.contentOffset;
|
||||||
}
|
}
|
||||||
// 溢出屏幕顶部
|
// 溢出屏幕顶部
|
||||||
if (contentRect.top < 0) {
|
if (contentRect.top < 0) {
|
||||||
top = triggerRect.height + props.contentOffset;
|
top = triggerRect.scrollBottom + props.contentOffset;
|
||||||
}
|
}
|
||||||
// 溢出屏幕左边
|
// 溢出屏幕左边
|
||||||
if (contentRect.left < 0) {
|
if (contentRect.left < 0) {
|
||||||
@ -258,11 +295,11 @@ const getFitPlacement = (
|
|||||||
}
|
}
|
||||||
// 溢出屏幕左边
|
// 溢出屏幕左边
|
||||||
if (contentRect.left < 0) {
|
if (contentRect.left < 0) {
|
||||||
left = triggerRect.width + props.contentOffset;
|
left = triggerRect.scrollRight + props.contentOffset;
|
||||||
}
|
}
|
||||||
// 溢出屏幕右边
|
// 溢出屏幕右边
|
||||||
if (contentRect.right > windowWidth.value) {
|
if (contentRect.right > windowWidth.value) {
|
||||||
left = -(contentRect.width + props.contentOffset);
|
left = triggerRect.scrollLeft - contentRect.width - props.contentOffset;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -274,8 +311,8 @@ const getFitPlacement = (
|
|||||||
|
|
||||||
const getContentOffset = (
|
const getContentOffset = (
|
||||||
placement: DropdownPlacement,
|
placement: DropdownPlacement,
|
||||||
triggerRect: DOMRect,
|
triggerRect: ElementScrollRect,
|
||||||
contentRect: DOMRect,
|
contentRect: ElementScrollRect,
|
||||||
isAlignPoint?: boolean
|
isAlignPoint?: boolean
|
||||||
) => {
|
) => {
|
||||||
if (isAlignPoint) {
|
if (isAlignPoint) {
|
||||||
@ -287,63 +324,71 @@ const getContentOffset = (
|
|||||||
switch (placement) {
|
switch (placement) {
|
||||||
case "top":
|
case "top":
|
||||||
return {
|
return {
|
||||||
top: -contentRect.height - props.contentOffset,
|
top: triggerRect.scrollTop - contentRect.height - props.contentOffset,
|
||||||
left: -(contentRect.width - triggerRect.width) / 2,
|
left:
|
||||||
|
triggerRect.scrollLeft +
|
||||||
|
Math.round((triggerRect.width - contentRect.width) / 2),
|
||||||
};
|
};
|
||||||
case "top-left":
|
case "top-left":
|
||||||
return {
|
return {
|
||||||
top: -contentRect.height - props.contentOffset,
|
top: triggerRect.scrollTop - contentRect.height - props.contentOffset,
|
||||||
left: 0,
|
left: triggerRect.scrollLeft,
|
||||||
};
|
};
|
||||||
case "top-right":
|
case "top-right":
|
||||||
return {
|
return {
|
||||||
top: -contentRect.height - props.contentOffset,
|
top: triggerRect.scrollTop - contentRect.height - props.contentOffset,
|
||||||
left: -(contentRect.width - triggerRect.width),
|
left: triggerRect.scrollRight - contentRect.width,
|
||||||
};
|
};
|
||||||
case "bottom":
|
case "bottom":
|
||||||
return {
|
return {
|
||||||
top: triggerRect.height + props.contentOffset,
|
top: triggerRect.scrollBottom + props.contentOffset,
|
||||||
left: -(contentRect.width - triggerRect.width) / 2,
|
left:
|
||||||
|
triggerRect.scrollLeft +
|
||||||
|
Math.round((triggerRect.width - contentRect.width) / 2),
|
||||||
};
|
};
|
||||||
case "bottom-left":
|
case "bottom-left":
|
||||||
return {
|
return {
|
||||||
top: triggerRect.height + props.contentOffset,
|
top: triggerRect.scrollBottom + props.contentOffset,
|
||||||
left: 0,
|
left: triggerRect.scrollLeft,
|
||||||
};
|
};
|
||||||
case "bottom-right":
|
case "bottom-right":
|
||||||
return {
|
return {
|
||||||
top: triggerRect.height + props.contentOffset,
|
top: triggerRect.scrollBottom + props.contentOffset,
|
||||||
left: -(contentRect.width - triggerRect.width),
|
left: triggerRect.scrollRight - contentRect.width,
|
||||||
};
|
};
|
||||||
case "right":
|
case "right":
|
||||||
return {
|
return {
|
||||||
top: -(contentRect.height - triggerRect.height) / 2,
|
top:
|
||||||
left: triggerRect.width + props.contentOffset,
|
triggerRect.scrollTop +
|
||||||
|
Math.round((triggerRect.height - contentRect.height) / 2),
|
||||||
|
left: triggerRect.scrollRight + props.contentOffset,
|
||||||
};
|
};
|
||||||
case "right-top":
|
case "right-top":
|
||||||
return {
|
return {
|
||||||
top: 0,
|
top: triggerRect.scrollTop,
|
||||||
left: triggerRect.width + props.contentOffset,
|
left: triggerRect.scrollRight + props.contentOffset,
|
||||||
};
|
};
|
||||||
case "right-bottom":
|
case "right-bottom":
|
||||||
return {
|
return {
|
||||||
top: -(contentRect.height - triggerRect.height),
|
top: triggerRect.scrollBottom - contentRect.height,
|
||||||
left: triggerRect.width + props.contentOffset,
|
left: triggerRect.scrollRight + props.contentOffset,
|
||||||
};
|
};
|
||||||
case "left":
|
case "left":
|
||||||
return {
|
return {
|
||||||
top: -(contentRect.height - triggerRect.height) / 2,
|
top:
|
||||||
left: -(contentRect.width + props.contentOffset),
|
triggerRect.scrollTop +
|
||||||
|
Math.round((triggerRect.height - contentRect.height) / 2),
|
||||||
|
left: triggerRect.scrollLeft - contentRect.width - props.contentOffset,
|
||||||
};
|
};
|
||||||
case "left-top":
|
case "left-top":
|
||||||
return {
|
return {
|
||||||
top: 0,
|
top: triggerRect.scrollTop,
|
||||||
left: -(contentRect.width + props.contentOffset),
|
left: triggerRect.scrollLeft - contentRect.width - props.contentOffset,
|
||||||
};
|
};
|
||||||
case "left-bottom":
|
case "left-bottom":
|
||||||
return {
|
return {
|
||||||
top: -(contentRect.height - triggerRect.height),
|
top: triggerRect.scrollBottom - contentRect.height,
|
||||||
left: -(contentRect.width + props.contentOffset),
|
left: triggerRect.scrollLeft - contentRect.width - props.contentOffset,
|
||||||
};
|
};
|
||||||
default:
|
default:
|
||||||
return {
|
return {
|
||||||
@ -376,7 +421,7 @@ const handleScroll = useThrottleFn(() => {
|
|||||||
if (openState.value) {
|
if (openState.value) {
|
||||||
updateContentStyle();
|
updateContentStyle();
|
||||||
}
|
}
|
||||||
}, 250);
|
}, 10);
|
||||||
|
|
||||||
const handleClick = () => {
|
const handleClick = () => {
|
||||||
if (props.disabled || (openState.value && !props.clickToClose)) {
|
if (props.disabled || (openState.value && !props.clickToClose)) {
|
||||||
@ -387,7 +432,7 @@ const handleClick = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleContextMenuClick = (e: Event) => {
|
const handleContextMenuClick = (e: MouseEvent) => {
|
||||||
if (props.disabled || (openState.value && !props.clickToClose)) {
|
if (props.disabled || (openState.value && !props.clickToClose)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -400,20 +445,30 @@ const handleContextMenuClick = (e: Event) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleMouseEnter = () => {
|
const handleMouseEnter = (e: MouseEvent) => {
|
||||||
if (props.disabled || !triggerMethods.value.includes("hover")) {
|
if (props.disabled || !triggerMethods.value.includes("hover")) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
open(props.mouseEnterDelay);
|
open(props.mouseEnterDelay);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleMouseLeave = () => {
|
const handleMouseEnterWithContext = (e: MouseEvent) => {
|
||||||
|
dropdownCtx?.onMouseenter(e);
|
||||||
|
handleMouseEnter(e);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleMouseLeave = (e: MouseEvent) => {
|
||||||
if (props.disabled || !triggerMethods.value.includes("hover")) {
|
if (props.disabled || !triggerMethods.value.includes("hover")) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
hide(props.mouseLeaveDelay);
|
hide(props.mouseLeaveDelay);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleMouseLeaveWithContext = (e: MouseEvent) => {
|
||||||
|
dropdownCtx?.onMouseleave(e);
|
||||||
|
handleMouseLeave(e);
|
||||||
|
};
|
||||||
|
|
||||||
const handleFocusin = () => {
|
const handleFocusin = () => {
|
||||||
if (props.disabled || !triggerMethods.value.includes("focus")) {
|
if (props.disabled || !triggerMethods.value.includes("focus")) {
|
||||||
return;
|
return;
|
||||||
@ -431,6 +486,27 @@ const handleFocusout = () => {
|
|||||||
hide();
|
hide();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const addChildRef = (ref: any) => {
|
||||||
|
childrenRefs.add(ref);
|
||||||
|
dropdownCtx?.addChildRef(ref);
|
||||||
|
};
|
||||||
|
const removeChildRef = (ref: any) => {
|
||||||
|
childrenRefs.delete(ref);
|
||||||
|
dropdownCtx?.removeChildRef(ref);
|
||||||
|
};
|
||||||
|
|
||||||
|
provide(
|
||||||
|
dropdownInjectionKey,
|
||||||
|
reactive({
|
||||||
|
onMouseenter: handleMouseEnterWithContext,
|
||||||
|
onMouseleave: handleMouseLeaveWithContext,
|
||||||
|
addChildRef,
|
||||||
|
removeChildRef,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
dropdownCtx?.addChildRef(contentRef);
|
||||||
|
|
||||||
const { stop: removeContentResizeObserver } = useResizeObserver(
|
const { stop: removeContentResizeObserver } = useResizeObserver(
|
||||||
contentRef,
|
contentRef,
|
||||||
() => {
|
() => {
|
||||||
@ -449,14 +525,22 @@ const { stop: removeTriggerResizeObserver } = useResizeObserver(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
onClickOutside(dropdownRef, () => {
|
onClickOutside(dropdownRef, (e) => {
|
||||||
if (props.clickOutsideToClose) {
|
if (
|
||||||
hide();
|
!props.clickOutsideToClose ||
|
||||||
|
dropdownRef.value?.contains(e.target as HTMLElement) ||
|
||||||
|
contentRef.value?.contains(e.target as HTMLElement)
|
||||||
|
)
|
||||||
|
return;
|
||||||
|
for (const item of childrenRefs) {
|
||||||
|
if (item.value?.contains(e.target as HTMLElement)) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
hide();
|
||||||
});
|
});
|
||||||
|
|
||||||
let scrollElements: HTMLElement[] | undefined;
|
let scrollElements: HTMLElement[] | undefined;
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
if (props.updateAtScroll) {
|
if (props.updateAtScroll) {
|
||||||
scrollElements = getScrollElements(dropdownRef.value);
|
scrollElements = getScrollElements(dropdownRef.value);
|
||||||
@ -467,6 +551,7 @@ onMounted(() => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
|
dropdownCtx?.removeChildRef(contentRef);
|
||||||
if (scrollElements) {
|
if (scrollElements) {
|
||||||
for (const item of scrollElements) {
|
for (const item of scrollElements) {
|
||||||
item.removeEventListener("scroll", handleScroll);
|
item.removeEventListener("scroll", handleScroll);
|
||||||
@ -509,8 +594,8 @@ defineExpose({ open, hide, toggle });
|
|||||||
<div
|
<div
|
||||||
ref="dropdownRef"
|
ref="dropdownRef"
|
||||||
class="layui-dropdown"
|
class="layui-dropdown"
|
||||||
@mouseenter="handleMouseEnter()"
|
@mouseenter="handleMouseEnter"
|
||||||
@mouseleave="handleMouseLeave()"
|
@mouseleave="handleMouseLeave"
|
||||||
@focusin="handleFocusin()"
|
@focusin="handleFocusin()"
|
||||||
@focusout="handleFocusout()"
|
@focusout="handleFocusout()"
|
||||||
:class="{ 'layui-dropdown-up': openState }"
|
:class="{ 'layui-dropdown-up': openState }"
|
||||||
@ -518,12 +603,17 @@ defineExpose({ open, hide, toggle });
|
|||||||
<div @click="handleClick()" @contextmenu="handleContextMenuClick">
|
<div @click="handleClick()" @contextmenu="handleContextMenuClick">
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
</div>
|
</div>
|
||||||
|
<Teleport :to="containerRef" :disabled="!renderToBody">
|
||||||
<dl
|
<dl
|
||||||
|
v-show="openState"
|
||||||
ref="contentRef"
|
ref="contentRef"
|
||||||
class="layui-anim layui-anim-upbit"
|
class="layui-dropdown-content layui-anim layui-anim-upbit"
|
||||||
:style="contentStyle"
|
:style="contentStyle"
|
||||||
|
@mouseenter="handleMouseEnterWithContext"
|
||||||
|
@mouseleave="handleMouseLeaveWithContext"
|
||||||
>
|
>
|
||||||
<slot name="content"></slot>
|
<slot name="content"></slot>
|
||||||
</dl>
|
</dl>
|
||||||
|
</Teleport>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -12,3 +12,25 @@ export type DropdownPlacement =
|
|||||||
| "left"
|
| "left"
|
||||||
| "left-top"
|
| "left-top"
|
||||||
| "left-bottom";
|
| "left-bottom";
|
||||||
|
|
||||||
|
export interface ElementScrollRect {
|
||||||
|
top: number;
|
||||||
|
bottom: number;
|
||||||
|
left: number;
|
||||||
|
right: number;
|
||||||
|
scrollTop: number;
|
||||||
|
scrollBottom: number;
|
||||||
|
scrollLeft: number;
|
||||||
|
scrollRight: number;
|
||||||
|
width: number;
|
||||||
|
height: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DropdownContext {
|
||||||
|
onMouseenter: Function;
|
||||||
|
onMouseleave: Function;
|
||||||
|
addChildRef: Function;
|
||||||
|
removeChildRef: Function;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const dropdownInjectionKey = Symbol("dropdownInjectKey");
|
||||||
|
Loading…
Reference in New Issue
Block a user