♻️(component): [subMenu]重构 subMenu
subMenu 重构,默认插槽渲染行为和 dropdown一致,支持更多场景 点击 menuItem 关闭悬浮菜单 popupMenu 支持侧边,横向菜单 dropdown 监听窗口 resize
This commit is contained in:
parent
8ea3ae78b0
commit
a31b33fca7
@ -621,6 +621,7 @@ onMounted(() => {
|
||||
item.addEventListener("scroll", handleScroll);
|
||||
}
|
||||
}
|
||||
window.addEventListener("resize", handleScroll);
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
@ -633,6 +634,7 @@ onBeforeUnmount(() => {
|
||||
}
|
||||
removeContentResizeObserver();
|
||||
removeTriggerResizeObserver();
|
||||
window.removeEventListener("resize", handleScroll);
|
||||
});
|
||||
|
||||
watch(
|
||||
@ -664,7 +666,7 @@ defineExpose({ show, hide, toggle });
|
||||
:renderFunc="onlyChildRenderFunc"
|
||||
v-bind="$attrs"
|
||||
></RenderFunction>
|
||||
<TeleportWrapper :to="popupContainer">
|
||||
<TeleportWrapper :to="popupContainer" :disabled="disabled">
|
||||
<div
|
||||
v-if="openState"
|
||||
ref="contentRef"
|
||||
|
@ -6,6 +6,7 @@ export default {
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, ComputedRef, inject, ref, Ref, useSlots } from "vue";
|
||||
import { DropdownContext, dropdownInjectionKey } from "../dropdown/interface";
|
||||
import useLevel from "../menu/useLevel";
|
||||
import LayTooltip from "../tooltip/index.vue";
|
||||
|
||||
@ -21,8 +22,14 @@ const selectedKey: Ref<string> = inject("selectedKey") as Ref<string>;
|
||||
const isTree = inject("isTree") as ComputedRef<boolean>;
|
||||
const isCollapse = inject("isCollapse") as ComputedRef<boolean | string>;
|
||||
const theme = inject("menuTheme") as Ref<string>;
|
||||
const dropdownCtx = inject<DropdownContext | undefined>(
|
||||
dropdownInjectionKey,
|
||||
undefined
|
||||
);
|
||||
|
||||
const selectHandle = function () {
|
||||
selectedKey.value = props.id;
|
||||
dropdownCtx?.hide();
|
||||
};
|
||||
|
||||
const needTooltip = computed(
|
||||
|
@ -16,24 +16,42 @@ export interface LaySubMenuPopupProps {
|
||||
}
|
||||
const props = defineProps<LaySubMenuPopupProps>();
|
||||
|
||||
const { level } = useLevel();
|
||||
const isTree: Ref<boolean> = inject("isTree") as Ref<boolean>;
|
||||
const openKeys: Ref<string[]> = inject("openKeys") as Ref<string[]>;
|
||||
const theme = inject("menuTheme") as Ref<string>;
|
||||
const computedTheme = computed(() => {
|
||||
return theme.value === "light" ? "-light" : "";
|
||||
});
|
||||
|
||||
const isOpen = computed(() => {
|
||||
return openKeys.value.includes(props.id);
|
||||
});
|
||||
|
||||
const computedTheme = computed(() => {
|
||||
if (isTree.value) {
|
||||
return theme.value === "light" ? "-light" : "";
|
||||
}
|
||||
return theme.value === "light" ? "" : "-light";
|
||||
});
|
||||
|
||||
const computedExpandIcon = computed(() => {
|
||||
if (isTree.value) return "layui-icon-right";
|
||||
return level.value === 2 ? "layui-icon-down" : "layui-icon-right";
|
||||
});
|
||||
|
||||
const computedPlacement = computed(() => {
|
||||
return !isTree.value && level.value === 2 ? "bottom-start" : "right-start";
|
||||
});
|
||||
|
||||
const computedTrigger = computed(() => {
|
||||
return !isTree.value && level.value === 2 ? "click" : "hover";
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<lay-dropdown
|
||||
trigger="hover"
|
||||
placement="right-start"
|
||||
:trigger="computedTrigger"
|
||||
:placement="computedPlacement"
|
||||
:autoFitMinWidth="false"
|
||||
:contentOffset="3"
|
||||
popupContainer="body"
|
||||
updateAtScroll
|
||||
class="layui-sub-menu-popup"
|
||||
>
|
||||
@ -54,7 +72,7 @@ const isOpen = computed(() => {
|
||||
<!-- 扩展 -->
|
||||
<span v-if="$slots.expandIcon" class="layui-nav-more">
|
||||
<slot name="expandIcon">
|
||||
<lay-icon type="layui-icon-right"></lay-icon>
|
||||
<lay-icon :type="computedExpandIcon" />
|
||||
</slot>
|
||||
</span>
|
||||
</a>
|
||||
|
@ -5,17 +5,7 @@ export default {
|
||||
</script>
|
||||
|
||||
<script setup lang="ts">
|
||||
import {
|
||||
computed,
|
||||
inject,
|
||||
onBeforeUnmount,
|
||||
ref,
|
||||
Ref,
|
||||
useSlots,
|
||||
watch,
|
||||
watchEffect,
|
||||
} from "vue";
|
||||
import { onClickOutside } from "@vueuse/core";
|
||||
import { computed, inject, ref, Ref, useSlots, watchEffect } from "vue";
|
||||
import LayTransition from "../transition/index.vue";
|
||||
import SubMenuPopup from "./SubMenuPopup.vue";
|
||||
import { provideLevel, default as useLevel } from "../menu/useLevel";
|
||||
@ -43,28 +33,25 @@ const isOpen = computed(() => {
|
||||
return openKeys.value.includes(props.id);
|
||||
});
|
||||
|
||||
const subMenuRef = ref<HTMLElement>();
|
||||
const position = ref<String>();
|
||||
const nextLevel = computed(() => level.value + 1);
|
||||
|
||||
provideLevel(nextLevel);
|
||||
|
||||
const needPopup = ref(false);
|
||||
watchEffect(() => {
|
||||
const _isCollapse = isCollapse.value === true || isCollapse.value === "true";
|
||||
if (_isCollapse && level.value === 1) {
|
||||
// 动画结束后改变
|
||||
setTimeout(() => {
|
||||
if (isTree.value) {
|
||||
const _isCollapse =
|
||||
isCollapse.value === true || isCollapse.value === "true";
|
||||
if (_isCollapse && level.value === 1) {
|
||||
// 动画结束后改变
|
||||
setTimeout(() => {
|
||||
needPopup.value = isTree.value && _isCollapse;
|
||||
}, 200);
|
||||
} else {
|
||||
needPopup.value = isTree.value && _isCollapse;
|
||||
}, 200);
|
||||
} else {
|
||||
needPopup.value = isTree.value && _isCollapse;
|
||||
}
|
||||
});
|
||||
|
||||
watch(isOpen, () => {
|
||||
if (isOpen.value && position.value !== "left-nav") {
|
||||
setTimeout(setPosition, 0);
|
||||
}
|
||||
} else if (slots.default && slots.default().length > 0) {
|
||||
needPopup.value = true;
|
||||
}
|
||||
});
|
||||
|
||||
@ -79,33 +66,6 @@ const openHandle = function () {
|
||||
openKeys.value = newOpenKeys;
|
||||
}
|
||||
};
|
||||
|
||||
const setPosition = function () {
|
||||
if (!isTree.value || !subMenuRef.value) {
|
||||
return;
|
||||
}
|
||||
const offsetWidth = subMenuRef.value.offsetWidth;
|
||||
if (
|
||||
window.innerWidth <
|
||||
subMenuRef.value.getBoundingClientRect().left + offsetWidth + 10
|
||||
) {
|
||||
position.value = "left-nav";
|
||||
} else {
|
||||
position.value = "";
|
||||
}
|
||||
};
|
||||
|
||||
onClickOutside(subMenuRef, (event: PointerEvent) => {
|
||||
if (!isTree.value) {
|
||||
let index = openKeys.value.indexOf(props.id);
|
||||
if (index != -1) {
|
||||
openKeys.value.splice(index, 1);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
window.addEventListener("resize", setPosition);
|
||||
onBeforeUnmount(() => window.removeEventListener("resize", setPosition));
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@ -141,15 +101,6 @@ onBeforeUnmount(() => window.removeEventListener("resize", setPosition));
|
||||
</div>
|
||||
</lay-transition>
|
||||
</template>
|
||||
<template v-else>
|
||||
<dl
|
||||
ref="subMenuRef"
|
||||
class="layui-nav-child layui-anim layui-anim-upbit"
|
||||
:class="[{ 'layui-show': isOpen }, position]"
|
||||
>
|
||||
<slot></slot>
|
||||
</dl>
|
||||
</template>
|
||||
</li>
|
||||
<SubMenuPopup v-else :id="id">
|
||||
<template v-if="slots.icon" #icon>
|
||||
|
Loading…
x
Reference in New Issue
Block a user