@bit-sun/business-component 4.2.5-per-alpha.1 → 4.2.5-per-alpha.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.fatherrc.ts +4 -0
- package/dist/index.esm.js +909 -601
- package/dist/index.js +909 -601
- package/package.json +5 -4
- package/src/components/Business/BsLayouts/Components/CustomerMenu/globalMenu/DrawContent.tsx +152 -53
- package/src/components/Business/BsLayouts/Components/CustomerMenu/index.tsx +13 -10
- package/src/components/Business/BsLayouts/index.tsx +153 -288
- package/src/components/Business/BsSulaQueryTable/index.tsx +592 -162
- package/src/components/Business/BsSulaQueryTable/setting.tsx +34 -24
- package/src/components/Business/HomePageWrapper/index.tsx +43 -13
- package/src/components/Business/JsonQueryTable/configTree/index.js +29 -2
- package/src/components/Functional/QueryMutipleSelect/index.tsx +33 -4
|
@@ -364,17 +364,7 @@ class BasicLayout extends React.PureComponent {
|
|
|
364
364
|
pathToRegexp,
|
|
365
365
|
} = this.props;
|
|
366
366
|
|
|
367
|
-
|
|
368
|
-
window.testTabDeletion = this.testTabDeletion;
|
|
369
|
-
window.countTabPaneDOMNodes = this.countTabPaneDOMNodes;
|
|
370
|
-
window.testDeleteTab = (key) => {
|
|
371
|
-
console.log(`[测试] 手动删除页签: ${key}`);
|
|
372
|
-
this.tabActions.remove(key);
|
|
373
|
-
};
|
|
374
|
-
window.forceCleanupDOM = this.forceCleanupDOM;
|
|
375
|
-
window.analyzeMemoryLeaks = this.analyzeMemoryLeaks;
|
|
376
|
-
window.forceClearTabPanes = this.forceClearTabPanes;
|
|
377
|
-
console.log('[调试工具] 已暴露全局方法: window.testTabDeletion(), window.countTabPaneDOMNodes(), window.testDeleteTab(key), window.forceCleanupDOM(), window.analyzeMemoryLeaks(), window.forceClearTabPanes()');
|
|
367
|
+
|
|
378
368
|
|
|
379
369
|
let istParent = 0;
|
|
380
370
|
|
|
@@ -628,16 +618,71 @@ class BasicLayout extends React.PureComponent {
|
|
|
628
618
|
});
|
|
629
619
|
this.timeoutIds.clear();
|
|
630
620
|
|
|
621
|
+
// 清理DOM缓存引用
|
|
622
|
+
if (this.cachedTabsElements) {
|
|
623
|
+
this.cachedTabsElements.globalTabsNav = null;
|
|
624
|
+
this.cachedTabsElements.globalTabsNavWrap = null;
|
|
625
|
+
this.cachedTabsElements = null;
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
// 清理ref引用
|
|
629
|
+
if (this.allFunc && this.allFunc.current) {
|
|
630
|
+
this.allFunc.current = null;
|
|
631
|
+
}
|
|
632
|
+
if (this.customerMenuRef && this.customerMenuRef.current) {
|
|
633
|
+
this.customerMenuRef.current = null;
|
|
634
|
+
}
|
|
635
|
+
if (this.actionRef && this.actionRef.current) {
|
|
636
|
+
this.actionRef.current = null;
|
|
637
|
+
}
|
|
638
|
+
|
|
631
639
|
// 清理实例属性
|
|
632
640
|
this.routerArray = null;
|
|
633
641
|
this.authMenuPathList = null;
|
|
634
642
|
this.docsId = null;
|
|
635
643
|
this.lastTwoRouterArray = null;
|
|
636
|
-
this.cachedTabsElements = null;
|
|
637
644
|
this.cachedBreadcrumbNameMap = null;
|
|
638
645
|
this.cachedWeiqianduanProps = null;
|
|
639
646
|
this.cachedOperationsSlot = null;
|
|
640
647
|
this.lastIsSliderState = null;
|
|
648
|
+
|
|
649
|
+
// 清理菜单容器的事件监听器
|
|
650
|
+
const menuContainer = document.querySelector('.sub_menu_content');
|
|
651
|
+
if (menuContainer) {
|
|
652
|
+
menuContainer.removeEventListener('click', this.handleMenuContainerClick);
|
|
653
|
+
// 清理所有菜单项的data属性和引用
|
|
654
|
+
const menuItems = menuContainer.querySelectorAll('[data-menu-item]');
|
|
655
|
+
menuItems.forEach(item => {
|
|
656
|
+
// 从WeakMap中移除引用
|
|
657
|
+
if (this.menuItemsWeakMap && this.menuItemsWeakMap.has(item)) {
|
|
658
|
+
this.menuItemsWeakMap.delete(item);
|
|
659
|
+
}
|
|
660
|
+
// 清理data属性
|
|
661
|
+
item.removeAttribute('data-menu-item');
|
|
662
|
+
item.removeAttribute('data-item-path');
|
|
663
|
+
item.removeAttribute('data-has-children');
|
|
664
|
+
});
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
// 清理WeakMap
|
|
668
|
+
if (this.menuItemsWeakMap) {
|
|
669
|
+
// WeakMap会自动清理,但显式清空以确保
|
|
670
|
+
this.menuItemsWeakMap = null;
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
// 清理方法引用,断开闭包链
|
|
674
|
+
this.handleMenuClick = null;
|
|
675
|
+
this.handleMenuContainerClick = null;
|
|
676
|
+
this.getMenuDom = null;
|
|
677
|
+
this.setShowMenu = null;
|
|
678
|
+
this.getTabsNavElements = null;
|
|
679
|
+
this.setTabNavTransLate = null;
|
|
680
|
+
this.checkisNavSlide = null;
|
|
681
|
+
|
|
682
|
+
// 强制触发垃圾回收(如果可用)
|
|
683
|
+
if (window.gc && typeof window.gc === 'function') {
|
|
684
|
+
setTimeout(() => window.gc(), 0);
|
|
685
|
+
}
|
|
641
686
|
}
|
|
642
687
|
|
|
643
688
|
parseQueryString = (queryString) => {
|
|
@@ -737,14 +782,12 @@ class BasicLayout extends React.PureComponent {
|
|
|
737
782
|
};
|
|
738
783
|
|
|
739
784
|
getDictionaryTextByValue = (dicCode: string, value: string) => {
|
|
740
|
-
let startPerformance = performance.now();
|
|
741
785
|
if (window.dicDataTextValue) {
|
|
742
786
|
const dicDataTextValue = window.dicDataTextValue;
|
|
743
787
|
let dicData = [];
|
|
744
788
|
|
|
745
789
|
dicData = dicDataTextValue[dicCode];
|
|
746
790
|
|
|
747
|
-
let endPerformance1 = performance.now();
|
|
748
791
|
|
|
749
792
|
if (value === undefined) return "-";
|
|
750
793
|
|
|
@@ -753,7 +796,6 @@ class BasicLayout extends React.PureComponent {
|
|
|
753
796
|
return value;
|
|
754
797
|
}
|
|
755
798
|
|
|
756
|
-
let endPerformance = performance.now();
|
|
757
799
|
|
|
758
800
|
return dicData[value] || value;
|
|
759
801
|
}
|
|
@@ -838,143 +880,18 @@ class BasicLayout extends React.PureComponent {
|
|
|
838
880
|
this.tabActions[action](targetKey);
|
|
839
881
|
};
|
|
840
882
|
|
|
841
|
-
// DOM节点计数辅助函数
|
|
842
|
-
countTabPaneDOMNodes = () => {
|
|
843
|
-
const tabPanes = document.querySelectorAll('.ant-tabs-tabpane');
|
|
844
|
-
const globalTabsTabPanes = document.querySelectorAll('#globalTabs .ant-tabs-tabpane');
|
|
845
|
-
const activeTabPanes = document.querySelectorAll('#globalTabs .ant-tabs-tabpane-active');
|
|
846
|
-
const hiddenTabPanes = document.querySelectorAll('#globalTabs .ant-tabs-tabpane:not(.ant-tabs-tabpane-active)');
|
|
847
|
-
|
|
848
|
-
console.log(`[DOM计数] 全局TabPane节点数: ${tabPanes.length}, globalTabs内TabPane节点数: ${globalTabsTabPanes.length}`);
|
|
849
|
-
console.log(`[DOM计数] 活跃TabPane节点数: ${activeTabPanes.length}, 非活跃TabPane节点数: ${hiddenTabPanes.length}`);
|
|
850
|
-
|
|
851
|
-
// 详细列出每个TabPane的key和状态
|
|
852
|
-
globalTabsTabPanes.forEach((pane, index) => {
|
|
853
|
-
const isActive = pane.classList.contains('ant-tabs-tabpane-active');
|
|
854
|
-
const key = pane.getAttribute('data-node-key') || pane.id || `未知-${index}`;
|
|
855
|
-
console.log(`[DOM详情] TabPane ${index + 1}: key=${key}, 活跃=${isActive}`);
|
|
856
|
-
});
|
|
857
|
-
|
|
858
|
-
return {
|
|
859
|
-
total: tabPanes.length,
|
|
860
|
-
globalTabs: globalTabsTabPanes.length,
|
|
861
|
-
active: activeTabPanes.length,
|
|
862
|
-
hidden: hiddenTabPanes.length
|
|
863
|
-
};
|
|
864
|
-
};
|
|
865
883
|
|
|
866
|
-
// 测试方法:验证页签删除后DOM状态
|
|
867
|
-
testTabDeletion = () => {
|
|
868
|
-
console.log('=== 页签删除测试开始 ===');
|
|
869
|
-
console.log('当前页签状态:', this.state.listenRouterState.map(item => item.key));
|
|
870
|
-
console.log('当前活跃页签:', this.state.activeKey);
|
|
871
|
-
this.countTabPaneDOMNodes();
|
|
872
|
-
|
|
873
|
-
// 提供删除建议
|
|
874
|
-
const { listenRouterState } = this.state;
|
|
875
|
-
if (listenRouterState.length > 1) {
|
|
876
|
-
const testKey = listenRouterState.find(item => item.key !== '/')?.key;
|
|
877
|
-
if (testKey) {
|
|
878
|
-
console.log(`建议测试:删除页签 ${testKey}`);
|
|
879
|
-
console.log(`执行命令:window.testDeleteTab('${testKey}')`);
|
|
880
|
-
}
|
|
881
|
-
}
|
|
882
|
-
console.log('=== 页签删除测试结束 ===');
|
|
883
|
-
};
|
|
884
884
|
|
|
885
|
-
// 强制清理DOM节点的方法
|
|
886
|
-
forceCleanupDOM = () => {
|
|
887
|
-
console.log('[强制清理] 开始强制清理DOM节点...');
|
|
888
|
-
const beforeCount = this.countTabPaneDOMNodes();
|
|
889
|
-
console.log(`[强制清理] 清理前DOM节点数: ${beforeCount.total}`);
|
|
890
|
-
|
|
891
|
-
// 强制垃圾回收
|
|
892
|
-
if (window.gc) {
|
|
893
|
-
window.gc();
|
|
894
|
-
console.log('[强制清理] 已触发垃圾回收');
|
|
895
|
-
}
|
|
896
|
-
|
|
897
|
-
// 清理所有可能的引用
|
|
898
|
-
const tabsContainer = document.getElementById('globalTabs');
|
|
899
|
-
if (tabsContainer) {
|
|
900
|
-
const tabPanes = tabsContainer.querySelectorAll('.ant-tabs-tabpane');
|
|
901
|
-
tabPanes.forEach((pane, index) => {
|
|
902
|
-
if (pane.style.display === 'none' || pane.getAttribute('aria-hidden') === 'true') {
|
|
903
|
-
console.log(`[强制清理] 发现隐藏的TabPane节点 ${index}, 尝试清理...`);
|
|
904
|
-
// 清理事件监听器
|
|
905
|
-
const clone = pane.cloneNode(true);
|
|
906
|
-
pane.parentNode?.replaceChild(clone, pane);
|
|
907
|
-
}
|
|
908
|
-
});
|
|
909
|
-
}
|
|
910
|
-
|
|
911
|
-
setTimeout(() => {
|
|
912
|
-
const afterCount = this.countTabPaneDOMNodes();
|
|
913
|
-
console.log(`[强制清理] 清理后DOM节点数: ${afterCount.total}`);
|
|
914
|
-
console.log(`[强制清理] DOM节点减少: ${beforeCount.total - afterCount.total}`);
|
|
915
|
-
}, 200);
|
|
916
|
-
};
|
|
917
885
|
|
|
918
|
-
// 分析内存泄漏的方法
|
|
919
|
-
analyzeMemoryLeaks = () => {
|
|
920
|
-
console.log('[内存分析] 开始分析可能的内存泄漏...');
|
|
921
|
-
|
|
922
|
-
// 检查全局事件监听器
|
|
923
|
-
const listeners = window.getEventListeners ? window.getEventListeners(document) : {};
|
|
924
|
-
console.log('[内存分析] 全局事件监听器:', listeners);
|
|
925
|
-
|
|
926
|
-
// 检查定时器
|
|
927
|
-
console.log('[内存分析] 当前活跃定时器数量:', Object.keys(window).filter(key => key.includes('timeout') || key.includes('interval')).length);
|
|
928
|
-
|
|
929
|
-
// 检查TabPane节点详情
|
|
930
|
-
const tabsContainer = document.getElementById('globalTabs');
|
|
931
|
-
if (tabsContainer) {
|
|
932
|
-
const tabPanes = tabsContainer.querySelectorAll('.ant-tabs-tabpane');
|
|
933
|
-
console.log(`[内存分析] 发现 ${tabPanes.length} 个TabPane节点:`);
|
|
934
|
-
tabPanes.forEach((pane, index) => {
|
|
935
|
-
const key = pane.getAttribute('data-node-key') || pane.id;
|
|
936
|
-
const isVisible = pane.style.display !== 'none' && pane.getAttribute('aria-hidden') !== 'true';
|
|
937
|
-
const hasContent = pane.children.length > 0;
|
|
938
|
-
console.log(` TabPane ${index}: key=${key}, visible=${isVisible}, hasContent=${hasContent}, children=${pane.children.length}`);
|
|
939
|
-
});
|
|
940
|
-
}
|
|
941
|
-
|
|
942
|
-
// 检查React组件实例
|
|
943
|
-
const reactInstances = document.querySelectorAll('[data-reactroot], [data-react-checksum]');
|
|
944
|
-
console.log(`[内存分析] React实例数量: ${reactInstances.length}`);
|
|
945
|
-
};
|
|
946
886
|
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
const tabsContainer = document.getElementById('globalTabs');
|
|
953
|
-
if (tabsContainer) {
|
|
954
|
-
const tabPanes = tabsContainer.querySelectorAll('.ant-tabs-tabpane');
|
|
955
|
-
console.log(`[强制清除] 发现 ${tabPanes.length} 个TabPane节点,准备清除...`);
|
|
956
|
-
|
|
957
|
-
tabPanes.forEach((pane, index) => {
|
|
958
|
-
const key = pane.getAttribute('data-node-key') || pane.id;
|
|
959
|
-
const isActive = !pane.getAttribute('aria-hidden') && pane.style.display !== 'none';
|
|
960
|
-
|
|
961
|
-
if (!isActive) {
|
|
962
|
-
console.log(`[强制清除] 移除非活跃TabPane ${index} (key: ${key})`);
|
|
963
|
-
pane.remove();
|
|
964
|
-
}
|
|
965
|
-
});
|
|
966
|
-
}
|
|
967
|
-
|
|
968
|
-
setTimeout(() => {
|
|
969
|
-
const afterCount = this.countTabPaneDOMNodes();
|
|
970
|
-
console.log(`[强制清除] 清除前: ${beforeCount.total}, 清除后: ${afterCount.total}, 减少: ${beforeCount.total - afterCount.total}`);
|
|
971
|
-
}, 100);
|
|
972
|
-
};
|
|
887
|
+
|
|
888
|
+
|
|
889
|
+
|
|
890
|
+
|
|
891
|
+
|
|
973
892
|
|
|
974
893
|
tabActions: any = {
|
|
975
894
|
remove: (targetKey: string) => {
|
|
976
|
-
console.log(`[页签删除] 开始删除页签: ${targetKey}`);
|
|
977
|
-
this.countTabPaneDOMNodes();
|
|
978
895
|
|
|
979
896
|
const { listenRouterState, activeKey, customerMatchs, listenRouterKey } =
|
|
980
897
|
this.state;
|
|
@@ -1024,12 +941,6 @@ class BasicLayout extends React.PureComponent {
|
|
|
1024
941
|
pathname: newKey,
|
|
1025
942
|
});
|
|
1026
943
|
this.checkisNavSlide();
|
|
1027
|
-
|
|
1028
|
-
// 延迟检查DOM节点变化,确保React完成渲染
|
|
1029
|
-
setTimeout(() => {
|
|
1030
|
-
console.log(`[页签删除] 删除页签 ${targetKey} 后的DOM状态:`);
|
|
1031
|
-
this.countTabPaneDOMNodes();
|
|
1032
|
-
}, 100);
|
|
1033
944
|
},
|
|
1034
945
|
);
|
|
1035
946
|
},
|
|
@@ -1069,29 +980,57 @@ class BasicLayout extends React.PureComponent {
|
|
|
1069
980
|
this.setShowMenu(false);
|
|
1070
981
|
};
|
|
1071
982
|
|
|
983
|
+
// 使用WeakMap存储菜单项引用,避免强引用
|
|
984
|
+
menuItemsWeakMap = new WeakMap();
|
|
985
|
+
|
|
986
|
+
// 容器级别的事件委托处理器
|
|
987
|
+
handleMenuContainerClick = (event) => {
|
|
988
|
+
const target = event.target.closest('[data-menu-item]');
|
|
989
|
+
if (!target) return;
|
|
990
|
+
|
|
991
|
+
const itemPath = target.getAttribute('data-item-path');
|
|
992
|
+
const hasChildren = target.getAttribute('data-has-children') === 'true';
|
|
993
|
+
|
|
994
|
+
if (!hasChildren && itemPath) {
|
|
995
|
+
// 从WeakMap中获取完整的item对象
|
|
996
|
+
const item = this.menuItemsWeakMap.get(target) || { path: itemPath };
|
|
997
|
+
this.handleMenuClick(item);
|
|
998
|
+
}
|
|
999
|
+
};
|
|
1000
|
+
|
|
1072
1001
|
getMenuDom = (menuData) => {
|
|
1073
|
-
return menuData.map((item) =>
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
}
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1002
|
+
return menuData.map((item, index) => {
|
|
1003
|
+
const hasChildren = item.children || !item.component;
|
|
1004
|
+
|
|
1005
|
+
return (
|
|
1006
|
+
<div key={`${item.path || item.name}-${index}`}>
|
|
1007
|
+
<div
|
|
1008
|
+
data-menu-item="true"
|
|
1009
|
+
data-item-path={item.path}
|
|
1010
|
+
data-has-children={hasChildren}
|
|
1011
|
+
className={`${'menu_item'} ${hasChildren ? '' : 'link_style'}`}
|
|
1012
|
+
style={{
|
|
1013
|
+
fontWeight: hasChildren ? 'bolder' : '400',
|
|
1014
|
+
paddingLeft: '10px',
|
|
1015
|
+
marginTop: hasChildren ? '5px' : '0px',
|
|
1016
|
+
fontSize: hasChildren ? '14px' : '12px',
|
|
1017
|
+
cursor: hasChildren ? 'default' : 'pointer',
|
|
1018
|
+
}}
|
|
1019
|
+
ref={(el) => {
|
|
1020
|
+
// 使用WeakMap存储元素与item的关联
|
|
1021
|
+
if (el && !hasChildren) {
|
|
1022
|
+
this.menuItemsWeakMap.set(el, item);
|
|
1023
|
+
}
|
|
1024
|
+
}}
|
|
1025
|
+
>
|
|
1026
|
+
{item.name}
|
|
1027
|
+
</div>
|
|
1028
|
+
{!!item.children &&
|
|
1029
|
+
!!item.children.length &&
|
|
1030
|
+
this.getMenuDom(item.children)}
|
|
1089
1031
|
</div>
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
this.getMenuDom(item.children)}
|
|
1093
|
-
</div>
|
|
1094
|
-
));
|
|
1032
|
+
);
|
|
1033
|
+
});
|
|
1095
1034
|
};
|
|
1096
1035
|
|
|
1097
1036
|
setShowMenu = debounce((isShow) => {
|
|
@@ -1675,7 +1614,7 @@ class BasicLayout extends React.PureComponent {
|
|
|
1675
1614
|
tabBarGutter={8}
|
|
1676
1615
|
onEdit={this.onEdit}
|
|
1677
1616
|
tabBarExtraContent={OperationsSlot}
|
|
1678
|
-
destroyInactiveTabPane={true}
|
|
1617
|
+
// destroyInactiveTabPane={true}
|
|
1679
1618
|
animated={false}
|
|
1680
1619
|
hideAdd
|
|
1681
1620
|
ref={(tabsRef) => {
|
|
@@ -1740,6 +1679,7 @@ class BasicLayout extends React.PureComponent {
|
|
|
1740
1679
|
onMouseLeave={() => {
|
|
1741
1680
|
this.setShowMenu(false);
|
|
1742
1681
|
}}
|
|
1682
|
+
onClick={this.handleMenuContainerClick}
|
|
1743
1683
|
className={'sub_menu_content'}
|
|
1744
1684
|
style={{ display: showSubMenu && !collapse ? 'block' : 'none' }}
|
|
1745
1685
|
>
|
|
@@ -1754,119 +1694,24 @@ class BasicLayout extends React.PureComponent {
|
|
|
1754
1694
|
class WrapperComponent extends React.Component {
|
|
1755
1695
|
constructor(props) {
|
|
1756
1696
|
super(props);
|
|
1757
|
-
console.log(`WrapperComponent 构造函数: 页签 ${props.item.key} 创建`);
|
|
1758
1697
|
|
|
1759
|
-
//
|
|
1760
|
-
this.domObserver = null;
|
|
1698
|
+
// 初始化组件状态
|
|
1761
1699
|
this.isUnmounted = false;
|
|
1762
|
-
|
|
1763
|
-
// 统计当前DOM节点数
|
|
1764
|
-
setTimeout(() => {
|
|
1765
|
-
const tabPanes = document.querySelectorAll('#globalTabs .ant-tabs-tabpane');
|
|
1766
|
-
console.log(`[组件创建] 页签 ${props.item.key} 创建后,DOM中TabPane节点数: ${tabPanes.length}`);
|
|
1767
|
-
}, 0);
|
|
1768
1700
|
}
|
|
1769
1701
|
|
|
1770
1702
|
componentDidMount() {
|
|
1771
|
-
|
|
1772
|
-
const tabPanes = document.querySelectorAll('#globalTabs .ant-tabs-tabpane');
|
|
1773
|
-
console.log(`[组件挂载] 页签 ${this.props.item.key} 挂载后,DOM中TabPane节点数: ${tabPanes.length}`);
|
|
1774
|
-
|
|
1775
|
-
// 设置MutationObserver监控DOM变化
|
|
1776
|
-
this.setupDOMObserver();
|
|
1703
|
+
// 组件挂载完成
|
|
1777
1704
|
}
|
|
1778
1705
|
|
|
1779
|
-
|
|
1780
|
-
if (this.domObserver || this.isUnmounted) return;
|
|
1781
|
-
|
|
1782
|
-
const globalTabsContainer = document.getElementById('globalTabs');
|
|
1783
|
-
if (!globalTabsContainer) return;
|
|
1784
|
-
|
|
1785
|
-
this.domObserver = new MutationObserver((mutations) => {
|
|
1786
|
-
if (this.isUnmounted) return;
|
|
1787
|
-
|
|
1788
|
-
mutations.forEach((mutation) => {
|
|
1789
|
-
if (mutation.type === 'childList') {
|
|
1790
|
-
// 检查是否有TabPane节点被添加或删除
|
|
1791
|
-
const addedTabPanes = Array.from(mutation.addedNodes).filter(node =>
|
|
1792
|
-
node.nodeType === Node.ELEMENT_NODE &&
|
|
1793
|
-
node.classList &&
|
|
1794
|
-
node.classList.contains('ant-tabs-tabpane')
|
|
1795
|
-
);
|
|
1796
|
-
|
|
1797
|
-
const removedTabPanes = Array.from(mutation.removedNodes).filter(node =>
|
|
1798
|
-
node.nodeType === Node.ELEMENT_NODE &&
|
|
1799
|
-
node.classList &&
|
|
1800
|
-
node.classList.contains('ant-tabs-tabpane')
|
|
1801
|
-
);
|
|
1802
|
-
|
|
1803
|
-
if (addedTabPanes.length > 0) {
|
|
1804
|
-
console.log(`[DOM监控] 检测到 ${addedTabPanes.length} 个TabPane节点被添加`);
|
|
1805
|
-
addedTabPanes.forEach(node => {
|
|
1806
|
-
const key = node.getAttribute('data-node-key') || '未知';
|
|
1807
|
-
console.log(`[DOM监控] 添加的TabPane: ${key}`);
|
|
1808
|
-
});
|
|
1809
|
-
}
|
|
1810
|
-
|
|
1811
|
-
if (removedTabPanes.length > 0) {
|
|
1812
|
-
console.log(`[DOM监控] 检测到 ${removedTabPanes.length} 个TabPane节点被删除`);
|
|
1813
|
-
removedTabPanes.forEach(node => {
|
|
1814
|
-
const key = node.getAttribute('data-node-key') || '未知';
|
|
1815
|
-
console.log(`[DOM监控] 删除的TabPane: ${key}`);
|
|
1816
|
-
|
|
1817
|
-
// 检查是否是当前组件对应的TabPane
|
|
1818
|
-
if (key === this.props.item.key) {
|
|
1819
|
-
console.log(`[DOM监控] 当前组件 ${this.props.item.key} 对应的TabPane已从DOM中删除`);
|
|
1820
|
-
}
|
|
1821
|
-
});
|
|
1822
|
-
}
|
|
1823
|
-
|
|
1824
|
-
// 统计当前DOM中的TabPane数量
|
|
1825
|
-
const currentTabPanes = document.querySelectorAll('#globalTabs .ant-tabs-tabpane');
|
|
1826
|
-
console.log(`[DOM监控] 当前DOM中TabPane节点总数: ${currentTabPanes.length}`);
|
|
1827
|
-
}
|
|
1828
|
-
});
|
|
1829
|
-
});
|
|
1830
|
-
|
|
1831
|
-
// 开始观察
|
|
1832
|
-
this.domObserver.observe(globalTabsContainer, {
|
|
1833
|
-
childList: true,
|
|
1834
|
-
subtree: true
|
|
1835
|
-
});
|
|
1836
|
-
|
|
1837
|
-
console.log(`[DOM监控] 已为页签 ${this.props.item.key} 设置DOM变化监控`);
|
|
1838
|
-
};
|
|
1706
|
+
|
|
1839
1707
|
|
|
1840
1708
|
componentWillUnmount() {
|
|
1841
|
-
console.log(`WrapperComponent 卸载: 页签 ${this.props.item.key} 组件正在销毁`);
|
|
1842
|
-
|
|
1843
1709
|
// 设置卸载标志
|
|
1844
1710
|
this.isUnmounted = true;
|
|
1845
1711
|
|
|
1846
|
-
|
|
1847
|
-
console.log(`[组件卸载] 页签 ${this.props.item.key} 卸载前,DOM中TabPane节点数: ${tabPanes.length}`);
|
|
1848
|
-
|
|
1849
|
-
// 清理MutationObserver
|
|
1850
|
-
if (this.domObserver) {
|
|
1851
|
-
this.domObserver.disconnect();
|
|
1852
|
-
this.domObserver = null;
|
|
1853
|
-
console.log(`[清理] 已断开页签 ${this.props.item.key} 的DOM监控`);
|
|
1854
|
-
}
|
|
1855
|
-
|
|
1856
|
-
// 强制清理所有可能的引用和事件监听器
|
|
1712
|
+
// 清理可能的DOM事件监听器
|
|
1857
1713
|
try {
|
|
1858
|
-
|
|
1859
|
-
if (this.props && typeof this.props === 'object') {
|
|
1860
|
-
Object.keys(this.props).forEach(key => {
|
|
1861
|
-
if (this.props[key] && typeof this.props[key] === 'object') {
|
|
1862
|
-
// 不直接删除props,但清理可能的循环引用
|
|
1863
|
-
console.log(`[清理] 检查prop: ${key}`);
|
|
1864
|
-
}
|
|
1865
|
-
});
|
|
1866
|
-
}
|
|
1867
|
-
|
|
1868
|
-
// 清理可能的DOM事件监听器
|
|
1869
|
-
const currentElement = document.querySelector(`#globalTabs .ant-tabs-tabpane[data-node-key="${this.props.item.key}"]`);
|
|
1714
|
+
const currentElement = document.getElementById('globalTabs-panel-' + this.props.item.key);
|
|
1870
1715
|
if (currentElement) {
|
|
1871
1716
|
// 移除所有可能的事件监听器
|
|
1872
1717
|
const events = ['click', 'mousedown', 'mouseup', 'mouseover', 'mouseout', 'focus', 'blur'];
|
|
@@ -1874,36 +1719,56 @@ class WrapperComponent extends React.Component {
|
|
|
1874
1719
|
currentElement.removeEventListener(eventType, this.handleEvent, true);
|
|
1875
1720
|
currentElement.removeEventListener(eventType, this.handleEvent, false);
|
|
1876
1721
|
});
|
|
1877
|
-
|
|
1722
|
+
|
|
1723
|
+
// 清理拖拽相关的事件监听器
|
|
1724
|
+
const dragEvents = ['dragstart', 'dragend', 'dragover', 'dragenter', 'dragleave', 'drop'];
|
|
1725
|
+
dragEvents.forEach(eventType => {
|
|
1726
|
+
currentElement.removeEventListener(eventType, this.handleDragEvent, true);
|
|
1727
|
+
currentElement.removeEventListener(eventType, this.handleDragEvent, false);
|
|
1728
|
+
});
|
|
1729
|
+
|
|
1730
|
+
// 清理react-dnd相关的属性和状态
|
|
1731
|
+
if (currentElement._reactInternalFiber) {
|
|
1732
|
+
delete currentElement._reactInternalFiber;
|
|
1733
|
+
}
|
|
1734
|
+
if (currentElement._reactInternalInstance) {
|
|
1735
|
+
delete currentElement._reactInternalInstance;
|
|
1736
|
+
}
|
|
1737
|
+
|
|
1738
|
+
// 清理可能的拖拽状态数据
|
|
1739
|
+
const dragStateKeys = Object.keys(currentElement).filter(key =>
|
|
1740
|
+
key.includes('drag') || key.includes('drop') || key.includes('dnd')
|
|
1741
|
+
);
|
|
1742
|
+
dragStateKeys.forEach(key => {
|
|
1743
|
+
try {
|
|
1744
|
+
delete currentElement[key];
|
|
1745
|
+
} catch (e) {
|
|
1746
|
+
// 忽略删除失败的情况
|
|
1747
|
+
}
|
|
1748
|
+
});
|
|
1749
|
+
|
|
1750
|
+
currentElement = null;
|
|
1878
1751
|
}
|
|
1879
1752
|
|
|
1880
1753
|
// 强制垃圾回收提示
|
|
1881
1754
|
if (window.gc && typeof window.gc === 'function') {
|
|
1882
1755
|
window.gc();
|
|
1883
|
-
console.log(`[清理] 已触发垃圾回收`);
|
|
1884
1756
|
}
|
|
1885
1757
|
|
|
1886
1758
|
} catch (error) {
|
|
1887
|
-
|
|
1759
|
+
// 清理过程中的错误处理
|
|
1888
1760
|
}
|
|
1889
|
-
|
|
1890
|
-
// 延迟检查卸载后的DOM状态
|
|
1891
|
-
setTimeout(() => {
|
|
1892
|
-
const tabPanesAfter = document.querySelectorAll('#globalTabs .ant-tabs-tabpane');
|
|
1893
|
-
console.log(`[组件卸载] 页签 ${this.props.item.key} 卸载后,DOM中TabPane节点数: ${tabPanesAfter.length}`);
|
|
1894
|
-
|
|
1895
|
-
// 强制检查内存使用情况
|
|
1896
|
-
if (window.performance && window.performance.memory) {
|
|
1897
|
-
const memory = window.performance.memory;
|
|
1898
|
-
console.log(`[内存监控] 卸载后内存使用: ${(memory.usedJSHeapSize / 1024 / 1024).toFixed(2)}MB / ${(memory.totalJSHeapSize / 1024 / 1024).toFixed(2)}MB`);
|
|
1899
|
-
}
|
|
1900
|
-
}, 100);
|
|
1901
1761
|
}
|
|
1902
1762
|
|
|
1903
1763
|
// 通用事件处理器,用于清理
|
|
1904
1764
|
handleEvent = (event) => {
|
|
1905
1765
|
// 空的事件处理器,仅用于清理时移除监听器
|
|
1906
1766
|
};
|
|
1767
|
+
|
|
1768
|
+
// 拖拽事件处理器,用于清理
|
|
1769
|
+
handleDragEvent = (event) => {
|
|
1770
|
+
// 空的拖拽事件处理器,仅用于清理时移除监听器
|
|
1771
|
+
};
|
|
1907
1772
|
|
|
1908
1773
|
shouldComponentUpdate(nextProps) {
|
|
1909
1774
|
if (window.__POWERED_BY_WUJIE__ && nextProps?.item?.key?.indexOf('edit-template-template') > -1) {
|