Skip to content

Commit 105ba3e

Browse files
GaoNeng-wWwkagol
authored andcommitted
refactor(menu): 重构类名
1 parent 03f3bd2 commit 105ba3e

File tree

9 files changed

+326
-147
lines changed

9 files changed

+326
-147
lines changed

packages/devui-vue/devui/menu/src/components/menu-item/menu-item.tsx

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { clearSelect } from '../../composables/use-layer-operate';
2-
import { defineComponent, getCurrentInstance, onMounted, ref, Transition, watch, inject, Ref, reactive, toRefs } from 'vue';
2+
import { defineComponent, getCurrentInstance, onMounted, ref, Transition, watch, inject, Ref, reactive, toRefs, computed } from 'vue';
33
import { MenuItemProps, menuItemProps } from './menu-item-types';
44
import { initSelect, addActiveParent, changeRoute } from './use-menu-item';
55
import { useClick } from '../../composables/use-click';
@@ -33,13 +33,12 @@ export default defineComponent({
3333
const useRouter = inject('useRouter') as boolean;
3434
const router = instance?.appContext.config.globalProperties.$router as Router;
3535

36-
const classObject: Record<string, boolean> = reactive({
36+
const classObject = computed(()=>({
3737
[`${ns.b()}-item`]: true,
3838
[`${ns.b()}-item-isCollapsed`]: isCollapsed.value,
39-
[`${ns.b()}-isCollapsed-item`]: isCollapsed.value,
4039
[menuItemSelect]: isSelect.value,
4140
[menuItemDisabled]: disabled.value,
42-
});
41+
}));
4342
const onClick = (e: MouseEvent) => {
4443
e.stopPropagation();
4544
const ele = e.currentTarget as HTMLElement;
@@ -80,13 +79,13 @@ export default defineComponent({
8079
const icons = <span class={`${ns.b()}-icon`}>{ctx.slots.icon?.()}</span>;
8180
const menuItems = ref(null);
8281
watch(disabled, () => {
83-
classObject[menuItemSelect] = false;
82+
classObject.value[menuItemSelect] = false;
8483
});
8584
watch(
8685
() => defaultSelectKey,
8786
(n) => {
8887
isSelect.value = initSelect(n, key, multiple, disabled);
89-
classObject[menuItemSelect] = isSelect.value;
88+
classObject.value[menuItemSelect] = isSelect.value;
9089
}
9190
);
9291
onMounted(() => {
@@ -121,11 +120,12 @@ export default defineComponent({
121120
}
122121
}
123122
});
123+
124124
return () => {
125125
return mode.value === 'vertical' ? (
126126
<div class={`${ns.b()}-item-vertical-wrapper`}>
127127
<li
128-
class={[classObject, props['disabled'] ? menuItemDisabled : '', isLayer1.value ? 'layer_1' : '']}
128+
class={classObject.value}
129129
onClick={onClick}
130130
ref={menuItems}>
131131
{ctx.slots.icon !== undefined && icons}
@@ -142,7 +142,7 @@ export default defineComponent({
142142
</div>
143143
) : (
144144
<li
145-
class={[classObject, props['disabled'] ? menuItemDisabled : '', isLayer1.value ? 'layer_1' : '']}
145+
class={classObject.value}
146146
onClick={onClick}
147147
ref={menuItems}>
148148
{ctx.slots.icon !== undefined && icons}

packages/devui-vue/devui/menu/src/components/sub-menu/sub-menu.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,11 @@ export default defineComponent({
2222
setup(props: SubMenuProps, ctx) {
2323
const isShow = ref(true);
2424
const {
25-
vnode: { key },
25+
vnode: { key }
2626
} = getCurrentInstance() as ComponentInternalInstance;
2727
const key_ = String(key);
2828
const isOpen = ref(false);
29-
const defaultOpenKeys = inject('openKeys') as string[];
29+
const defaultOpenKeys = inject('openKeys') as Ref<string[]>;
3030
const indent = inject('defaultIndent');
3131
const isCollapsed = inject('isCollapsed') as Ref<boolean>;
3232
const mode = inject('mode') as Ref<string>;
@@ -36,7 +36,7 @@ export default defineComponent({
3636
if (key_ === 'null') {
3737
console.warn(`[devui][menu]: Key can not be null`);
3838
} else {
39-
if (defaultOpenKeys.includes(key_)) {
39+
if (defaultOpenKeys.value.includes(key_)) {
4040
isOpen.value = true;
4141
} else {
4242
isOpen.value = false;
@@ -93,12 +93,12 @@ export default defineComponent({
9393
watch(
9494
() => defaultOpenKeys,
9595
(n) => {
96-
if (n.includes(key_)) {
96+
if (n.value.includes(key_)) {
9797
isOpen.value = true;
9898
} else {
9999
isOpen.value = false;
100100
}
101-
}
101+
},{deep: true}
102102
);
103103
onMounted(() => {
104104
const el = title.value as unknown as HTMLElement;
@@ -147,7 +147,7 @@ export default defineComponent({
147147
{props.title}
148148
</span>
149149
<i
150-
v-show={!isCollapsed.value}
150+
v-show={!isCollapsed.value && key !== 'overflowContainer'}
151151
class={{
152152
'icon icon-chevron-up': class_layer.value !== `layer_${subMenuClass}`,
153153
'icon icon-chevron-right': class_layer.value === `layer_${subMenuClass}`,

packages/devui-vue/devui/menu/src/components/sub-menu/use-sub-menu.ts

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,37 +9,36 @@ const menuItemHorizontalWrapperShow = `${ns.b()}-item-horizontal-wrapper-show`;
99
type mouseEventName = 'mouseenter' | 'mouseleave';
1010
export function useShowSubMenu(eventName: mouseEventName, e: MouseEvent, wrapper: HTMLElement): void {
1111
const target = e.currentTarget as EventTarget as HTMLElement;
12-
const subMenuTitle = target.children[0];
1312
const targetParent = target.parentElement;
1413
const wrapperChildren = wrapper.children;
1514
wrapper.style.padding = `0 20px !important`;
1615
if (eventName === 'mouseenter') {
17-
wrapper.classList.remove(menuItemHorizontalWrapperHidden);
18-
wrapper.classList.add(menuItemHorizontalWrapperShow);
1916
if (targetParent?.tagName === 'DIV') {
2017
wrapper.classList.add(`${ns.b()}-item-horizontal-wrapper-level`);
21-
const { top, left } = target.getClientRects()[0];
22-
const x = left + targetParent.clientWidth;
23-
const y = top;
24-
wrapper.style.top = `${y}px`;
25-
wrapper.style.left = `${x}px`;
18+
const { width } = target.getClientRects()[0];
19+
wrapper.style.top = `0px`;
20+
wrapper.style.left = `${width}px`;
2621
} else {
27-
const { top, left, height } = subMenuTitle.getClientRects()[0];
28-
const y = top + height;
29-
wrapper.style.top = `${y}px`;
30-
wrapper.style.left = `${left}px`;
22+
wrapper.style.top = `26px`;
23+
wrapper.style.left = `0px`;
3124
}
25+
wrapper.classList.remove(menuItemHorizontalWrapperHidden);
26+
wrapper.classList.add(menuItemHorizontalWrapperShow);
3227
for (let i = 0; i < wrapperChildren.length; i++) {
3328
const ul = wrapperChildren[i];
3429
if (ul.tagName === 'UL' && ul.classList.contains(subNs.b())) {
3530
const levelUlWrapper = ul.getElementsByClassName(`${ns.b()}-item-horizontal-wrapper`)[0];
3631
(ul as HTMLElement).addEventListener('mouseenter', (ev: MouseEvent) => {
3732
ev.stopPropagation();
3833
useShowSubMenu('mouseenter', ev, levelUlWrapper as Element as HTMLElement);
34+
levelUlWrapper.classList.remove(menuItemHorizontalWrapperHidden);
35+
levelUlWrapper.classList.add(menuItemHorizontalWrapperShow);
3936
});
4037
(ul as HTMLElement).addEventListener('mouseleave', (ev: MouseEvent) => {
4138
ev.stopPropagation();
4239
useShowSubMenu('mouseleave', ev, levelUlWrapper as Element as HTMLElement);
40+
levelUlWrapper.classList.remove(menuItemHorizontalWrapperShow);
41+
levelUlWrapper.classList.add(menuItemHorizontalWrapperHidden);
4342
});
4443
}
4544
}

packages/devui-vue/devui/menu/src/menu.tsx

Lines changed: 41 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,58 @@
1-
import { defineComponent, provide, ref, computed, onMounted } from 'vue';
1+
import { defineComponent, provide, ref, computed, onMounted, toRefs } from 'vue';
22
import type { ComponentPublicInstance } from 'vue';
33
import { menuProps, MenuProps } from './menu-types';
44
import './menu.scss';
55
import { setDefaultIndent } from './composables/use-layer-operate';
66
import SubMenu from './components/sub-menu/sub-menu';
77
import { useNamespace } from '../../shared/hooks/use-namespace';
8+
import { useShowSubMenu } from './components/sub-menu/use-sub-menu';
89

910
export default defineComponent({
1011
name: 'DMenu',
1112
props: menuProps,
1213
emits: ['select', 'deselect', 'submenu-change'],
1314
setup(props: MenuProps, ctx) {
1415
const ns = useNamespace('menu');
15-
16-
const isCollapsed = computed(() => props.collapsed);
17-
const mode = computed(() => props['mode']);
18-
provide('isCollapsed', isCollapsed);
16+
const {openKeys, mode, collapsed} = toRefs(props);
17+
provide('isCollapsed', collapsed);
1918
provide('defaultIndent', props['indentSize']);
2019
provide('multiple', props['multiple']);
21-
provide('openKeys', props.openKeys);
20+
provide('openKeys', openKeys);
2221
provide('defaultSelectKey', props.defaultSelectKeys);
2322
provide('mode', mode);
24-
provide('collapsedIndent', ref(props['collapsedIndent']));
23+
provide('collapsedIndent', props['collapsedIndent']);
2524
provide('rootMenuEmit', ctx.emit);
2625
provide('useRouter', props.router);
2726
setDefaultIndent(props['indentSize']);
2827
const menuRoot = ref(null);
2928
const overflow_container = ref<ComponentPublicInstance | null>(null);
3029
const overflowItemLength = ref(0);
30+
const rootClassName = computed(()=>({
31+
[`${ns.b()}`]: true,
32+
[`${ns.b()}-vertical`]: mode.value === 'vertical',
33+
[`${ns.b()}-horizontal`]: mode.value === 'horizontal',
34+
[`${ns.b()}-collapsed`]: collapsed.value
35+
}));
3136
onMounted(() => {
3237
if (props['mode'] === 'horizontal') {
38+
let flag = false;
3339
const overflowContainer = overflow_container.value?.$el as unknown as HTMLElement;
3440
const root = menuRoot.value as unknown as HTMLElement;
3541
const children = root.children;
3642
const container = overflowContainer.children[1];
43+
let preItem: HTMLElement | null;
3744
const ob = new IntersectionObserver(
3845
(entries: IntersectionObserverEntry[]) => {
3946
entries.forEach((v: IntersectionObserverEntry) => {
4047
if (!v.isIntersecting) {
41-
if (!v.target.classList.contains(`${ns.b()}-overflow-container`)) {
48+
const cloneNode = v.target.cloneNode(true) as Element as HTMLElement;
49+
preItem = v.target as Element as HTMLElement;
50+
if (v.target.classList.contains(`${ns.b()}-overflow-container`)){
51+
if (flag && v.target.previousElementSibling){
52+
root.appendChild(v.target.previousElementSibling);
53+
} else {flag = true;}
54+
} else {
4255
overflowItemLength.value += 1;
43-
const cloneNode = v.target.cloneNode(true) as Element as HTMLElement;
4456
(v.target as Element as HTMLElement).style.visibility = 'hidden';
4557
if (overflowContainer.nextSibling) {
4658
root.insertBefore(v.target, overflowContainer.nextSibling);
@@ -54,12 +66,27 @@ export default defineComponent({
5466
!v.target.classList.contains(`${ns.b()}-overflow-container`) &&
5567
(v.target as HTMLElement).style.visibility === 'hidden'
5668
) {
69+
console.log(v.target, preItem, v.target === preItem);
5770
ob.unobserve(v.target);
58-
root.insertBefore(container.children[container.children.length - 1], overflowContainer);
71+
const el = container.children[container.children.length - 1];
72+
root.insertBefore(el, overflowContainer);
5973
const obItem = overflowContainer.previousElementSibling;
6074
if (obItem) {
6175
ob.observe(obItem);
6276
}
77+
if (obItem?.classList.contains('devui-submenu')){
78+
const sub = obItem;
79+
const wrapper = obItem.children[1] as HTMLElement;
80+
(sub as HTMLElement).addEventListener('mouseenter', (ev: MouseEvent) => {
81+
console.log('emit');
82+
ev.stopPropagation();
83+
useShowSubMenu('mouseenter', ev, wrapper);
84+
});
85+
(sub as HTMLElement).addEventListener('mouseleave', (ev: MouseEvent) => {
86+
ev.stopPropagation();
87+
useShowSubMenu('mouseleave', ev, wrapper);
88+
});
89+
}
6390
(v.target as HTMLElement).style.visibility = '';
6491
v.target.remove();
6592
overflowItemLength.value -= 1;
@@ -70,6 +97,7 @@ export default defineComponent({
7097
{
7198
root: root,
7299
threshold: 1,
100+
rootMargin: '8px'
73101
}
74102
);
75103
for (let i = 0; i < children.length; i++) {
@@ -81,10 +109,9 @@ export default defineComponent({
81109
return (
82110
<ul
83111
ref={menuRoot}
84-
class={[`${ns.b()}`, `${ns.b()}-${props['mode']}`, props['collapsed'] ? `${ns.b()}-collapsed` : '']}
112+
class={rootClassName.value}
85113
style={[
86114
props['collapsed'] ? `width:${props['collapsedIndent'] * 2}px` : `width: ${props['width']}`,
87-
'overflow: hidden',
88115
'white-space: nowrap',
89116
]}>
90117
{ctx.slots.default?.()}
@@ -93,7 +120,8 @@ export default defineComponent({
93120
key="overflowContainer"
94121
title="..."
95122
class={`${ns.b()}-overflow-container`}
96-
v-show={overflowItemLength.value > 0}></SubMenu>
123+
v-show={overflowItemLength.value > 0 && mode.value === 'horizontal'}>
124+
</SubMenu>
97125
</ul>
98126
);
99127
};

packages/devui-vue/devui/menu/src/styles/clear.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,6 @@
77
ul,
88
li {
99
list-style: none;
10+
white-space: nowrap;
1011
}
1112
}

packages/devui-vue/devui/menu/src/styles/horizontal.scss

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -114,17 +114,21 @@
114114
}
115115

116116
div.#{$devui-prefix}-menu-item-horizontal-wrapper {
117-
transition: all $devui-animation-duration-fast $devui-animation-ease-in-smooth;
117+
transition:
118+
all $devui-animation-duration-fast $devui-animation-ease-in-smooth,
119+
left 0 linear;
118120
background: $devui-menu-bg;
121+
z-index: $devui-z-index-modal;
119122
}
120123

121124
div.#{$devui-prefix}-menu-item-horizontal-wrapper-show {
125+
transition: all $devui-animation-duration-fast $devui-animation-ease-in-smooth;
122126
opacity: 1;
123127
visibility: visible;
124-
max-height: calc(100vh - 100px);
128+
max-height: 100vh;
125129
padding: 10px 0 !important;
126130
border-radius: 8px;
127-
position: fixed;
131+
position: absolute;
128132

129133
.#{$devui-prefix}-menu-item {
130134
margin-top: 5px;
@@ -146,13 +150,12 @@
146150

147151
div.#{$devui-prefix}-menu-item-horizontal-wrapper-hidden {
148152
transition: all $devui-animation-duration-fast $devui-animation-ease-in-smooth;
149-
position: fixed;
150-
// margin-top: -5px;
153+
visibility: hidden;
154+
position: absolute;
151155
padding: 0 !important;
152156
max-height: 0;
153157
overflow: hidden;
154158
opacity: 0;
155-
156159
.#{$devui-prefix}-menu-item {
157160
margin-top: 5px;
158161
}

packages/devui-vue/devui/menu/src/styles/vertical.scss

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,6 @@
1010
border-right: $devui-line 1px solid;
1111
background: $devui-area !important;
1212

13-
* {
14-
transition: all $devui-animation-duration-fast $devui-animation-ease-in-smooth;
15-
}
16-
1713
::after {
1814
transition: all $devui-animation-duration-fast $devui-animation-ease-in-smooth;
1915
background: transparent;
@@ -31,11 +27,6 @@
3127
}
3228
}
3329

34-
li.#{$devui-prefix}-menu-isCollapsed-item {
35-
padding: 0;
36-
margin: auto;
37-
}
38-
3930
&.#{$devui-prefix}-menu-collapsed {
4031
.#{$devui-prefix}-menu-icon {
4132
margin: auto;

0 commit comments

Comments
 (0)