♻️(component): [subMenu]重构 subMenu

subMenu 重构,默认插槽渲染行为和 dropdown一致,支持更多场景
点击 menuItem 关闭悬浮菜单
popupMenu 支持侧边,横向菜单
dropdown 监听窗口
resize
This commit is contained in:
sight 2022-08-30 01:18:06 +08:00
parent 8ea3ae78b0
commit a31b33fca7
4 changed files with 48 additions and 70 deletions

View File

@ -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"

View File

@ -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(

View File

@ -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>

View File

@ -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>