Commit 6e03e05032474c858151b3835eb5318486a56729

Authored by vben
1 parent 41d79008

perf: perf context menu

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
@@ -19,7 +19,7 @@ @@ -19,7 +19,7 @@
19 } 19 }
20 20
21 > .basic-loading { 21 > .basic-loading {
22 - margin-bottom: 30%; 22 + margin-bottom: 15%;
23 } 23 }
24 } 24 }
25 } 25 }
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
@@ -20,7 +20,6 @@ @@ -20,7 +20,6 @@
20 20
21 &__left { 21 &__left {
22 display: flex; 22 display: flex;
23 - // flex-grow: 1;  
24 align-items: center; 23 align-items: center;
25 24
26 .layout-trigger { 25 .layout-trigger {
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;