Commit 6e03e05032474c858151b3835eb5318486a56729
1 parent
41d79008
perf: perf context menu
Showing
16 changed files
with
205 additions
and
176 deletions
src/components/ContextMenu/index.ts
1 | -import contextMenuVue from './src/index'; | ||
2 | -import { isClient } from '/@/utils/is'; | ||
3 | -import { Options, Props } from './src/types'; | ||
4 | -import { createVNode, render } from 'vue'; | ||
5 | -const menuManager: { | ||
6 | - domList: Element[]; | ||
7 | - resolve: Fn; | ||
8 | -} = { | ||
9 | - domList: [], | ||
10 | - resolve: () => {}, | ||
11 | -}; | ||
12 | -export const createContextMenu = function (options: Options) { | ||
13 | - const { event } = options || {}; | ||
14 | - try { | ||
15 | - event.preventDefault(); | ||
16 | - } catch (e) { | ||
17 | - console.log(e); | ||
18 | - } | ||
19 | - | ||
20 | - if (!isClient) return; | ||
21 | - return new Promise((resolve) => { | ||
22 | - const container = document.createElement('div'); | ||
23 | - const propsData: Partial<Props> = {}; | ||
24 | - if (options.styles !== undefined) propsData.styles = options.styles; | ||
25 | - if (options.items !== undefined) propsData.items = options.items; | ||
26 | - if (options.event !== undefined) { | ||
27 | - propsData.customEvent = event; | ||
28 | - propsData.axis = { x: event.clientX, y: event.clientY }; | ||
29 | - } | ||
30 | - const vm = createVNode(contextMenuVue, propsData); | ||
31 | - render(vm, container); | ||
32 | - const bodyClick = function () { | ||
33 | - menuManager.resolve(''); | ||
34 | - }; | ||
35 | - menuManager.domList.push(container); | ||
36 | - const remove = function () { | ||
37 | - menuManager.domList.forEach((dom: Element) => { | ||
38 | - try { | ||
39 | - document.body.removeChild(dom); | ||
40 | - } catch (error) {} | ||
41 | - }); | ||
42 | - document.body.removeEventListener('click', bodyClick); | ||
43 | - document.body.removeEventListener('scroll', bodyClick); | ||
44 | - }; | ||
45 | - menuManager.resolve = function (...arg: any) { | ||
46 | - resolve(arg[0]); | ||
47 | - remove(); | ||
48 | - }; | ||
49 | - remove(); | ||
50 | - document.body.appendChild(container); | ||
51 | - document.body.addEventListener('click', bodyClick); | ||
52 | - document.body.addEventListener('scroll', bodyClick); | ||
53 | - }); | ||
54 | -}; | ||
55 | -export const unMountedContextMenu = function () { | ||
56 | - if (menuManager) { | ||
57 | - menuManager.resolve(''); | ||
58 | - menuManager.domList = []; | ||
59 | - } | ||
60 | -}; | ||
61 | - | 1 | +export { createContextMenu, destroyContextMenu } from './src/createContextMenu'; |
62 | export * from './src/types'; | 2 | export * from './src/types'; |
src/components/ContextMenu/src/createContextMenu.ts
0 → 100644
1 | +import contextMenuVue from './index'; | ||
2 | +import { isClient } from '/@/utils/is'; | ||
3 | +import { CreateContextOptions, ContextMenuProps } from './types'; | ||
4 | +import { createVNode, render } from 'vue'; | ||
5 | + | ||
6 | +const menuManager: { | ||
7 | + domList: Element[]; | ||
8 | + resolve: Fn; | ||
9 | +} = { | ||
10 | + domList: [], | ||
11 | + resolve: () => {}, | ||
12 | +}; | ||
13 | + | ||
14 | +export const createContextMenu = function (options: CreateContextOptions) { | ||
15 | + const { event } = options || {}; | ||
16 | + | ||
17 | + event && event?.preventDefault(); | ||
18 | + | ||
19 | + if (!isClient) return; | ||
20 | + return new Promise((resolve) => { | ||
21 | + const body = document.body; | ||
22 | + | ||
23 | + const container = document.createElement('div'); | ||
24 | + const propsData: Partial<ContextMenuProps> = {}; | ||
25 | + if (options.styles) { | ||
26 | + propsData.styles = options.styles; | ||
27 | + } | ||
28 | + | ||
29 | + if (options.items) { | ||
30 | + propsData.items = options.items; | ||
31 | + } | ||
32 | + | ||
33 | + if (options.event) { | ||
34 | + propsData.customEvent = event; | ||
35 | + propsData.axis = { x: event.clientX, y: event.clientY }; | ||
36 | + } | ||
37 | + | ||
38 | + const vm = createVNode(contextMenuVue, propsData); | ||
39 | + render(vm, container); | ||
40 | + | ||
41 | + const handleClick = function () { | ||
42 | + menuManager.resolve(''); | ||
43 | + }; | ||
44 | + | ||
45 | + menuManager.domList.push(container); | ||
46 | + | ||
47 | + const remove = function () { | ||
48 | + menuManager.domList.forEach((dom: Element) => { | ||
49 | + try { | ||
50 | + dom && body.removeChild(dom); | ||
51 | + } catch (error) {} | ||
52 | + }); | ||
53 | + body.removeEventListener('click', handleClick); | ||
54 | + body.removeEventListener('scroll', handleClick); | ||
55 | + }; | ||
56 | + | ||
57 | + menuManager.resolve = function (...arg: any) { | ||
58 | + remove(); | ||
59 | + resolve(arg[0]); | ||
60 | + }; | ||
61 | + remove(); | ||
62 | + body.appendChild(container); | ||
63 | + body.addEventListener('click', handleClick); | ||
64 | + body.addEventListener('scroll', handleClick); | ||
65 | + }); | ||
66 | +}; | ||
67 | + | ||
68 | +export const destroyContextMenu = function () { | ||
69 | + if (menuManager) { | ||
70 | + menuManager.resolve(''); | ||
71 | + menuManager.domList = []; | ||
72 | + } | ||
73 | +}; |
src/components/ContextMenu/src/index.less
1 | @import (reference) '../../../design/index.less'; | 1 | @import (reference) '../../../design/index.less'; |
2 | 2 | ||
3 | +@default-height: 42px !important; | ||
4 | + | ||
5 | +@small-height: 36px !important; | ||
6 | + | ||
7 | +@large-height: 36px !important; | ||
8 | + | ||
3 | .item-style() { | 9 | .item-style() { |
4 | li { | 10 | li { |
5 | display: inline-block; | 11 | display: inline-block; |
6 | width: 100%; | 12 | width: 100%; |
7 | - height: 46px !important; | 13 | + height: @default-height; |
8 | margin: 0 !important; | 14 | margin: 0 !important; |
9 | - line-height: 46px; | 15 | + line-height: @default-height; |
10 | 16 | ||
11 | span { | 17 | span { |
12 | - line-height: 46px; | 18 | + line-height: @default-height; |
13 | } | 19 | } |
14 | 20 | ||
15 | > div { | 21 | > div { |
16 | margin: 0 !important; | 22 | margin: 0 !important; |
17 | } | 23 | } |
18 | 24 | ||
19 | - &:hover { | 25 | + &:not(.ant-menu-item-disabled):hover { |
20 | color: @text-color-base; | 26 | color: @text-color-base; |
21 | background: #eee; | 27 | background: #eee; |
22 | } | 28 | } |
@@ -27,10 +33,9 @@ | @@ -27,10 +33,9 @@ | ||
27 | position: fixed; | 33 | position: fixed; |
28 | top: 0; | 34 | top: 0; |
29 | left: 0; | 35 | left: 0; |
30 | - z-index: 1500; | 36 | + z-index: 200; |
31 | display: block; | 37 | display: block; |
32 | width: 156px; | 38 | width: 156px; |
33 | - min-width: 10rem; | ||
34 | margin: 0; | 39 | margin: 0; |
35 | list-style: none; | 40 | list-style: none; |
36 | background-color: #fff; | 41 | background-color: #fff; |
src/components/ContextMenu/src/index.tsx
1 | -import { | ||
2 | - defineComponent, | ||
3 | - nextTick, | ||
4 | - onMounted, | ||
5 | - reactive, | ||
6 | - computed, | ||
7 | - ref, | ||
8 | - unref, | ||
9 | - onUnmounted, | ||
10 | -} from 'vue'; | 1 | +import './index.less'; |
2 | + | ||
3 | +import type { ContextMenuItem, ItemContentProps } from './types'; | ||
4 | +import type { FunctionalComponent, CSSProperties } from 'vue'; | ||
5 | + | ||
6 | +import { defineComponent, nextTick, onMounted, computed, ref, unref, onUnmounted } from 'vue'; | ||
11 | 7 | ||
12 | -import { props } from './props'; | ||
13 | import Icon from '/@/components/Icon'; | 8 | import Icon from '/@/components/Icon'; |
14 | import { Menu, Divider } from 'ant-design-vue'; | 9 | import { Menu, Divider } from 'ant-design-vue'; |
15 | 10 | ||
16 | -import type { ContextMenuItem } from './types'; | 11 | +import { props } from './props'; |
17 | 12 | ||
18 | -import './index.less'; | ||
19 | const prefixCls = 'context-menu'; | 13 | const prefixCls = 'context-menu'; |
14 | + | ||
15 | +const ItemContent: FunctionalComponent<ItemContentProps> = (props) => { | ||
16 | + const { item } = props; | ||
17 | + return ( | ||
18 | + <span style="display: inline-block; width: 100%;" onClick={props.handler.bind(null, item)}> | ||
19 | + {props.showIcon && item.icon && <Icon class="mr-2" icon={item.icon} />} | ||
20 | + <span>{item.label}</span> | ||
21 | + </span> | ||
22 | + ); | ||
23 | +}; | ||
24 | + | ||
20 | export default defineComponent({ | 25 | export default defineComponent({ |
21 | name: 'ContextMenu', | 26 | name: 'ContextMenu', |
22 | props, | 27 | props, |
23 | setup(props) { | 28 | setup(props) { |
24 | - const wrapRef = ref<Nullable<HTMLDivElement>>(null); | ||
25 | - const state = reactive({ | ||
26 | - show: false, | ||
27 | - }); | 29 | + const wrapRef = ref<ElRef>(null); |
30 | + const showRef = ref(false); | ||
31 | + | ||
32 | + const getStyle = computed( | ||
33 | + (): CSSProperties => { | ||
34 | + const { axis, items, styles, width } = props; | ||
35 | + const { x, y } = axis || { x: 0, y: 0 }; | ||
36 | + const menuHeight = (items || []).length * 40; | ||
37 | + const menuWidth = width; | ||
38 | + const body = document.body; | ||
39 | + | ||
40 | + const left = body.clientWidth < x + menuWidth ? x - menuWidth : x; | ||
41 | + const top = body.clientHeight < y + menuHeight ? y - menuHeight : y; | ||
42 | + return { | ||
43 | + ...styles, | ||
44 | + width: `${width}px`, | ||
45 | + left: `${left + 1}px`, | ||
46 | + top: `${top + 1}px`, | ||
47 | + }; | ||
48 | + } | ||
49 | + ); | ||
28 | 50 | ||
29 | onMounted(() => { | 51 | onMounted(() => { |
30 | - nextTick(() => { | ||
31 | - state.show = true; | ||
32 | - }); | 52 | + nextTick(() => (showRef.value = true)); |
33 | }); | 53 | }); |
34 | 54 | ||
35 | onUnmounted(() => { | 55 | onUnmounted(() => { |
36 | const el = unref(wrapRef); | 56 | const el = unref(wrapRef); |
37 | el && document.body.removeChild(el); | 57 | el && document.body.removeChild(el); |
38 | }); | 58 | }); |
39 | - const getStyle = computed(() => { | ||
40 | - const { axis, items, styles, width } = props; | ||
41 | - const { x, y } = axis || { x: 0, y: 0 }; | ||
42 | - const menuHeight = (items || []).length * 40; | ||
43 | - const menuWidth = width; | ||
44 | - const body = document.body; | ||
45 | - return { | ||
46 | - ...(styles as any), | ||
47 | - width: `${width}px`, | ||
48 | - left: (body.clientWidth < x + menuWidth ? x - menuWidth : x) + 'px', | ||
49 | - top: (body.clientHeight < y + menuHeight ? y - menuHeight : y) + 'px', | ||
50 | - }; | ||
51 | - }); | ||
52 | 59 | ||
53 | function handleAction(item: ContextMenuItem, e: MouseEvent) { | 60 | function handleAction(item: ContextMenuItem, e: MouseEvent) { |
54 | - state.show = false; | ||
55 | const { handler, disabled } = item; | 61 | const { handler, disabled } = item; |
56 | - if (disabled) { | ||
57 | - return; | ||
58 | - } | ||
59 | - if (e) { | ||
60 | - e.stopPropagation(); | ||
61 | - e.preventDefault(); | ||
62 | - } | 62 | + if (disabled) return; |
63 | + showRef.value = false; | ||
63 | 64 | ||
64 | - handler && handler(); | ||
65 | - } | ||
66 | - | ||
67 | - function renderContent(item: ContextMenuItem) { | ||
68 | - const { icon, label } = item; | ||
69 | - | ||
70 | - const { showIcon } = props; | ||
71 | - return ( | ||
72 | - <span style="display: inline-block; width: 100%;" onClick={handleAction.bind(null, item)}> | ||
73 | - {showIcon && icon && <Icon class="mr-2" icon={icon} />} | ||
74 | - <span>{label}</span> | ||
75 | - </span> | ||
76 | - ); | 65 | + e?.stopPropagation(); |
66 | + e?.preventDefault(); | ||
67 | + handler?.(); | ||
77 | } | 68 | } |
78 | 69 | ||
79 | function renderMenuItem(items: ContextMenuItem[]) { | 70 | function renderMenuItem(items: ContextMenuItem[]) { |
80 | - return items.map((item, index) => { | 71 | + return items.map((item) => { |
81 | const { disabled, label, children, divider = false } = item; | 72 | const { disabled, label, children, divider = false } = item; |
82 | 73 | ||
83 | - const DividerComp = divider ? <Divider key={`d-${index}`} /> : null; | 74 | + const DividerComp = divider ? <Divider key={`d-${label}`} /> : null; |
84 | if (!children || children.length === 0) { | 75 | if (!children || children.length === 0) { |
85 | - return [ | ||
86 | - <Menu.Item disabled={disabled} class={`${prefixCls}__item`} key={label}> | ||
87 | - {() => [renderContent(item)]} | ||
88 | - </Menu.Item>, | ||
89 | - DividerComp, | ||
90 | - ]; | 76 | + return ( |
77 | + <> | ||
78 | + <Menu.Item disabled={disabled} class={`${prefixCls}__item`} key={label}> | ||
79 | + {() => [ | ||
80 | + <ItemContent showIcon={props.showIcon} item={item} handler={handleAction} />, | ||
81 | + ]} | ||
82 | + </Menu.Item> | ||
83 | + {DividerComp} | ||
84 | + </> | ||
85 | + ); | ||
91 | } | 86 | } |
92 | - return !state.show ? null : ( | ||
93 | - <Menu.SubMenu key={label} disabled={disabled} popupClassName={`${prefixCls}__popup `}> | 87 | + if (!unref(showRef)) return null; |
88 | + | ||
89 | + return ( | ||
90 | + <Menu.SubMenu key={label} disabled={disabled} popupClassName={`${prefixCls}__popup`}> | ||
94 | {{ | 91 | {{ |
95 | - title: () => renderContent(item), | ||
96 | - default: () => [renderMenuItem(children)], | 92 | + title: () => ( |
93 | + <ItemContent showIcon={props.showIcon} item={item} handler={handleAction} /> | ||
94 | + ), | ||
95 | + default: () => renderMenuItem(children), | ||
97 | }} | 96 | }} |
98 | </Menu.SubMenu> | 97 | </Menu.SubMenu> |
99 | ); | 98 | ); |
@@ -101,11 +100,12 @@ export default defineComponent({ | @@ -101,11 +100,12 @@ export default defineComponent({ | ||
101 | } | 100 | } |
102 | return () => { | 101 | return () => { |
103 | const { items } = props; | 102 | const { items } = props; |
104 | - return !state.show ? null : ( | 103 | + if (!unref(showRef)) return null; |
104 | + return ( | ||
105 | <Menu | 105 | <Menu |
106 | inlineIndent={12} | 106 | inlineIndent={12} |
107 | mode="vertical" | 107 | mode="vertical" |
108 | - class={[prefixCls]} | 108 | + class={prefixCls} |
109 | ref={wrapRef} | 109 | ref={wrapRef} |
110 | style={unref(getStyle)} | 110 | style={unref(getStyle)} |
111 | > | 111 | > |
src/components/ContextMenu/src/props.ts
1 | -import type { PropType } from 'vue'; | 1 | +import type { PropType, CSSProperties } from 'vue'; |
2 | import type { Axis, ContextMenuItem } from './types'; | 2 | import type { Axis, ContextMenuItem } from './types'; |
3 | export const props = { | 3 | export const props = { |
4 | width: { | 4 | width: { |
5 | type: Number as PropType<number>, | 5 | type: Number as PropType<number>, |
6 | - default: 180, | 6 | + default: 156, |
7 | }, | 7 | }, |
8 | customEvent: { | 8 | customEvent: { |
9 | type: Object as PropType<Event>, | 9 | type: Object as PropType<Event>, |
10 | default: null, | 10 | default: null, |
11 | }, | 11 | }, |
12 | styles: { | 12 | styles: { |
13 | - type: Object as PropType<any>, | 13 | + type: Object as PropType<CSSProperties>, |
14 | default: null, | 14 | default: null, |
15 | }, | 15 | }, |
16 | showIcon: { | 16 | showIcon: { |
@@ -31,8 +31,4 @@ export const props = { | @@ -31,8 +31,4 @@ export const props = { | ||
31 | return []; | 31 | return []; |
32 | }, | 32 | }, |
33 | }, | 33 | }, |
34 | - resolve: { | ||
35 | - type: Function as PropType<any>, | ||
36 | - default: null, | ||
37 | - }, | ||
38 | }; | 34 | }; |
src/components/ContextMenu/src/types.ts
@@ -11,15 +11,14 @@ export interface ContextMenuItem { | @@ -11,15 +11,14 @@ export interface ContextMenuItem { | ||
11 | divider?: boolean; | 11 | divider?: boolean; |
12 | children?: ContextMenuItem[]; | 12 | children?: ContextMenuItem[]; |
13 | } | 13 | } |
14 | -export interface Options { | 14 | +export interface CreateContextOptions { |
15 | event: MouseEvent; | 15 | event: MouseEvent; |
16 | icon?: string; | 16 | icon?: string; |
17 | styles?: any; | 17 | styles?: any; |
18 | items?: ContextMenuItem[]; | 18 | items?: ContextMenuItem[]; |
19 | } | 19 | } |
20 | 20 | ||
21 | -export type Props = { | ||
22 | - resolve?: (...arg: any) => void; | 21 | +export interface ContextMenuProps { |
23 | event?: MouseEvent; | 22 | event?: MouseEvent; |
24 | styles?: any; | 23 | styles?: any; |
25 | items: ContextMenuItem[]; | 24 | items: ContextMenuItem[]; |
@@ -27,4 +26,10 @@ export type Props = { | @@ -27,4 +26,10 @@ export type Props = { | ||
27 | axis?: Axis; | 26 | axis?: Axis; |
28 | width?: number; | 27 | width?: number; |
29 | showIcon?: boolean; | 28 | showIcon?: boolean; |
30 | -}; | 29 | +} |
30 | + | ||
31 | +export interface ItemContentProps { | ||
32 | + showIcon: boolean; | ||
33 | + item: ContextMenuItem; | ||
34 | + handler: Fn; | ||
35 | +} |
src/components/Drawer/src/BasicDrawer.tsx
@@ -22,7 +22,7 @@ export default defineComponent({ | @@ -22,7 +22,7 @@ export default defineComponent({ | ||
22 | props: basicProps, | 22 | props: basicProps, |
23 | emits: ['visible-change', 'ok', 'close', 'register'], | 23 | emits: ['visible-change', 'ok', 'close', 'register'], |
24 | setup(props, { slots, emit, attrs }) { | 24 | setup(props, { slots, emit, attrs }) { |
25 | - const scrollRef = ref<any>(null); | 25 | + const scrollRef = ref<ElRef>(null); |
26 | 26 | ||
27 | const visibleRef = ref(false); | 27 | const visibleRef = ref(false); |
28 | const propsRef = ref<Partial<DrawerProps> | null>(null); | 28 | const propsRef = ref<Partial<DrawerProps> | null>(null); |
src/components/Modal/src/BasicModal.tsx
@@ -22,7 +22,7 @@ export default defineComponent({ | @@ -22,7 +22,7 @@ export default defineComponent({ | ||
22 | setup(props, { slots, emit, attrs }) { | 22 | setup(props, { slots, emit, attrs }) { |
23 | const visibleRef = ref(false); | 23 | const visibleRef = ref(false); |
24 | const propsRef = ref<Partial<ModalProps> | null>(null); | 24 | const propsRef = ref<Partial<ModalProps> | null>(null); |
25 | - const modalWrapperRef = ref<any>(null); | 25 | + const modalWrapperRef = ref<ComponentRef>(null); |
26 | // modal Bottom and top height | 26 | // modal Bottom and top height |
27 | const extHeightRef = ref(0); | 27 | const extHeightRef = ref(0); |
28 | // Unexpanded height of the popup | 28 | // Unexpanded height of the popup |
src/components/Modal/src/ModalWrapper.tsx
@@ -55,7 +55,7 @@ export default defineComponent({ | @@ -55,7 +55,7 @@ export default defineComponent({ | ||
55 | emits: ['heightChange', 'getExtHeight'], | 55 | emits: ['heightChange', 'getExtHeight'], |
56 | setup(props: ModalWrapperProps, { slots, emit }) { | 56 | setup(props: ModalWrapperProps, { slots, emit }) { |
57 | const wrapperRef = ref<HTMLElement | null>(null); | 57 | const wrapperRef = ref<HTMLElement | null>(null); |
58 | - const spinRef = ref<any>(null); | 58 | + const spinRef = ref<ComponentRef>(null); |
59 | const realHeightRef = ref(0); | 59 | const realHeightRef = ref(0); |
60 | // 重试次数 | 60 | // 重试次数 |
61 | // let tryCount = 0; | 61 | // let tryCount = 0; |
@@ -126,6 +126,8 @@ export default defineComponent({ | @@ -126,6 +126,8 @@ export default defineComponent({ | ||
126 | await nextTick(); | 126 | await nextTick(); |
127 | const spinEl = unref(spinRef); | 127 | const spinEl = unref(spinRef); |
128 | 128 | ||
129 | + if (!spinEl) return; | ||
130 | + | ||
129 | const spinContainerEl = spinEl.$el.querySelector('.ant-spin-container') as HTMLElement; | 131 | const spinContainerEl = spinEl.$el.querySelector('.ant-spin-container') as HTMLElement; |
130 | if (!spinContainerEl) return; | 132 | if (!spinContainerEl) return; |
131 | 133 |
src/components/Table/src/BasicTable.vue
@@ -74,7 +74,7 @@ | @@ -74,7 +74,7 @@ | ||
74 | components: { Table, BasicForm }, | 74 | components: { Table, BasicForm }, |
75 | emits: ['fetch-success', 'fetch-error', 'selection-change', 'register'], | 75 | emits: ['fetch-success', 'fetch-error', 'selection-change', 'register'], |
76 | setup(props, { attrs, emit, slots }) { | 76 | setup(props, { attrs, emit, slots }) { |
77 | - const tableElRef = ref<any>(null); | 77 | + const tableElRef = ref<ComponentRef>(null); |
78 | const wrapRef = ref<Nullable<HTMLDivElement>>(null); | 78 | const wrapRef = ref<Nullable<HTMLDivElement>>(null); |
79 | const innerPropsRef = ref<Partial<BasicTableProps>>(); | 79 | const innerPropsRef = ref<Partial<BasicTableProps>>(); |
80 | const [registerForm, { getFieldsValue }] = useForm(); | 80 | const [registerForm, { getFieldsValue }] = useForm(); |
@@ -241,10 +241,8 @@ | @@ -241,10 +241,8 @@ | ||
241 | if (unref(getMergeProps).showSummary) { | 241 | if (unref(getMergeProps).showSummary) { |
242 | nextTick(() => { | 242 | nextTick(() => { |
243 | const tableEl = unref(tableElRef); | 243 | const tableEl = unref(tableElRef); |
244 | - if (!tableEl) { | ||
245 | - return; | ||
246 | - } | ||
247 | - const bodyDomList = tableEl.$el.querySelectorAll('.ant-table-body') as HTMLDivElement[]; | 244 | + if (!tableEl) return; |
245 | + const bodyDomList = tableEl.$el.querySelectorAll('.ant-table-body'); | ||
248 | const bodyDom = bodyDomList[0]; | 246 | const bodyDom = bodyDomList[0]; |
249 | useEventListener({ | 247 | useEventListener({ |
250 | el: bodyDom, | 248 | el: bodyDom, |
src/hooks/web/useContextMenu.ts
1 | import { onUnmounted, getCurrentInstance } from 'vue'; | 1 | import { onUnmounted, getCurrentInstance } from 'vue'; |
2 | -import { createContextMenu, unMountedContextMenu } from '/@/components/ContextMenu'; | 2 | +import { createContextMenu, destroyContextMenu } from '/@/components/ContextMenu'; |
3 | import type { ContextMenuItem } from '/@/components/ContextMenu'; | 3 | import type { ContextMenuItem } from '/@/components/ContextMenu'; |
4 | export type { ContextMenuItem }; | 4 | export type { ContextMenuItem }; |
5 | export function useContextMenu(authRemove = true) { | 5 | export function useContextMenu(authRemove = true) { |
6 | if (getCurrentInstance() && authRemove) { | 6 | if (getCurrentInstance() && authRemove) { |
7 | onUnmounted(() => { | 7 | onUnmounted(() => { |
8 | - unMountedContextMenu(); | 8 | + destroyContextMenu(); |
9 | }); | 9 | }); |
10 | } | 10 | } |
11 | - return [createContextMenu, unMountedContextMenu]; | 11 | + return [createContextMenu, destroyContextMenu]; |
12 | } | 12 | } |
src/layouts/default/content/index.less
src/layouts/default/header/LayoutHeader.tsx
@@ -60,10 +60,10 @@ export default defineComponent({ | @@ -60,10 +60,10 @@ export default defineComponent({ | ||
60 | }, | 60 | }, |
61 | }, | 61 | }, |
62 | setup(props) { | 62 | setup(props) { |
63 | - let logoEl: Element | null; | 63 | + let logoEl: Element | null | undefined; |
64 | 64 | ||
65 | const logoWidthRef = ref(200); | 65 | const logoWidthRef = ref(200); |
66 | - const logoRef = ref<any>(null); | 66 | + const logoRef = ref<ComponentRef>(null); |
67 | const { refreshPage } = useTabs(); | 67 | const { refreshPage } = useTabs(); |
68 | 68 | ||
69 | const { getShowTopMenu, getShowHeaderTrigger, getSplit, getTopMenuAlign } = useMenuSetting(); | 69 | const { getShowTopMenu, getShowHeaderTrigger, getSplit, getTopMenuAlign } = useMenuSetting(); |
@@ -91,7 +91,7 @@ export default defineComponent({ | @@ -91,7 +91,7 @@ export default defineComponent({ | ||
91 | if (!unref(getShowTopMenu)) return; | 91 | if (!unref(getShowTopMenu)) return; |
92 | let width = 0; | 92 | let width = 0; |
93 | if (!logoEl) { | 93 | if (!logoEl) { |
94 | - logoEl = logoRef.value.$el; | 94 | + logoEl = unref(logoRef)?.$el; |
95 | } else { | 95 | } else { |
96 | width += logoEl.clientWidth; | 96 | width += logoEl.clientWidth; |
97 | } | 97 | } |
src/layouts/default/header/LayoutMultipleHeader.tsx
@@ -39,26 +39,30 @@ export default defineComponent({ | @@ -39,26 +39,30 @@ export default defineComponent({ | ||
39 | return unref(getShowMultipleTab) && !unref(getFullContent); | 39 | return unref(getShowMultipleTab) && !unref(getFullContent); |
40 | }); | 40 | }); |
41 | 41 | ||
42 | - const getPlaceholderDomStyle = computed(() => { | ||
43 | - return { | ||
44 | - height: `${unref(placeholderHeightRef)}px`, | ||
45 | - }; | ||
46 | - }); | 42 | + const getPlaceholderDomStyle = computed( |
43 | + (): CSSProperties => { | ||
44 | + return { | ||
45 | + height: `${unref(placeholderHeightRef)}px`, | ||
46 | + }; | ||
47 | + } | ||
48 | + ); | ||
47 | 49 | ||
48 | const getIsShowPlaceholderDom = computed(() => { | 50 | const getIsShowPlaceholderDom = computed(() => { |
49 | return unref(getFixed) || unref(getShowFullHeaderRef); | 51 | return unref(getFixed) || unref(getShowFullHeaderRef); |
50 | }); | 52 | }); |
51 | 53 | ||
52 | - const getWrapStyle = computed(() => { | ||
53 | - const style: CSSProperties = {}; | ||
54 | - if (unref(getFixed)) { | ||
55 | - style.width = unref(getCalcContentWidth); | 54 | + const getWrapStyle = computed( |
55 | + (): CSSProperties => { | ||
56 | + const style: CSSProperties = {}; | ||
57 | + if (unref(getFixed)) { | ||
58 | + style.width = unref(getCalcContentWidth); | ||
59 | + } | ||
60 | + if (unref(getShowFullHeaderRef)) { | ||
61 | + style.top = `${unref(fullHeaderHeightRef)}px`; | ||
62 | + } | ||
63 | + return style; | ||
56 | } | 64 | } |
57 | - if (unref(getShowFullHeaderRef)) { | ||
58 | - style.top = `${unref(fullHeaderHeightRef)}px`; | ||
59 | - } | ||
60 | - return style; | ||
61 | - }); | 65 | + ); |
62 | 66 | ||
63 | const getIsFixed = computed(() => { | 67 | const getIsFixed = computed(() => { |
64 | return unref(getFixed) || unref(getShowFullHeaderRef); | 68 | return unref(getFixed) || unref(getShowFullHeaderRef); |
src/layouts/default/header/index.less
src/layouts/default/multitabs/index.less
@@ -40,9 +40,12 @@ | @@ -40,9 +40,12 @@ | ||
40 | height: 12px; | 40 | height: 12px; |
41 | font-size: 12px; | 41 | font-size: 12px; |
42 | color: inherit; | 42 | color: inherit; |
43 | + visibility: hidden; | ||
43 | transition: none; | 44 | transition: none; |
44 | 45 | ||
45 | &:hover { | 46 | &:hover { |
47 | + visibility: visible; | ||
48 | + | ||
46 | svg { | 49 | svg { |
47 | width: 0.8em; | 50 | width: 0.8em; |
48 | } | 51 | } |
@@ -69,6 +72,10 @@ | @@ -69,6 +72,10 @@ | ||
69 | display: none; | 72 | display: none; |
70 | } | 73 | } |
71 | 74 | ||
75 | + .ant-tabs-close-x { | ||
76 | + visibility: visible; | ||
77 | + } | ||
78 | + | ||
72 | svg { | 79 | svg { |
73 | width: 0.7em; | 80 | width: 0.7em; |
74 | fill: @white; | 81 | fill: @white; |