Sfoglia il codice sorgente

fix(comp): fix the memory overflow problem of component containing keywords

vben 4 anni fa
parent
commit
6b3195b4ca

+ 7 - 0
CHANGELOG.zh_CN.md

@@ -4,6 +4,10 @@
 
 - 移除左侧菜单搜索,新增顶部菜单搜索功能
 
+### ⚡ Performance Improvements
+
+- 异步引入组件
+
 ### 🎫 Chores
 
 - 返回顶部样式调整,避免遮住其他元素
@@ -14,6 +18,9 @@
 - 修复多级路由缓存导致组件渲染多次的问题
 - 修复地图图表切换后消失问题
 - 修复登录成功 notify 消失问题
+- 修改 `VirtualScroll`和`ImportExcel`组件名为`VScroll`与`ImpExcel`,暂时解决含有关键字的组件在 vue 模版内使用内存溢出
+- 修复 axios 大小写问题
+- 修复按钮样式问题
 
 ## 2.0.0-rc.13 (2020-12-10)
 

+ 6 - 2
src/components/Application/index.ts

@@ -1,9 +1,13 @@
 import { withInstall } from '../util';
 import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
 
-export const AppLocalePicker = createAsyncComponent(() => import('./src/AppLocalePicker.vue'));
+export const AppLocalePicker = createAsyncComponent(() => import('./src/AppLocalePicker.vue'), {
+  loading: true,
+});
 export const AppProvider = createAsyncComponent(() => import('./src/AppProvider.vue'));
-export const AppSearch = createAsyncComponent(() => import('./src/search/AppSearch.vue'));
+export const AppSearch = createAsyncComponent(() => import('./src/search/AppSearch.vue'), {
+  loading: true,
+});
 export const AppLogo = createAsyncComponent(() => import('./src/AppLogo.vue'));
 
 withInstall(AppLocalePicker, AppLogo, AppProvider, AppSearch);

+ 3 - 5
src/components/Button/src/BasicButton.vue

@@ -1,9 +1,9 @@
 <template>
   <Button v-bind="getBindValue" :class="[getColor, $attrs.class]">
     <template #default="data">
-      <Icon :icon="preIcon" :class="{ 'mr-1': !getIsCircleBtn }" v-if="preIcon" />
+      <Icon :icon="preIcon" v-if="preIcon" :size="14" />
       <slot v-bind="data" />
-      <Icon :icon="postIcon" :class="{ 'ml-1': !getIsCircleBtn }" v-if="postIcon" />
+      <Icon :icon="postIcon" v-if="postIcon" :size="14" />
     </template>
   </Button>
 </template>
@@ -27,8 +27,6 @@
       postIcon: propTypes.string,
     },
     setup(props, { attrs }) {
-      const getIsCircleBtn = computed(() => attrs.shape === 'circle');
-
       const getColor = computed(() => {
         const { color, disabled } = props;
         return {
@@ -41,7 +39,7 @@
         return { ...attrs, ...props };
       });
 
-      return { getBindValue, getColor, getIsCircleBtn };
+      return { getBindValue, getColor };
     },
   });
 </script>

+ 7 - 5
src/components/Container/index.ts

@@ -1,10 +1,12 @@
-import ScrollContainer from './src/ScrollContainer.vue';
-import CollapseContainer from './src/collapse/CollapseContainer.vue';
-import LazyContainer from './src/LazyContainer.vue';
 import { withInstall } from '../util';
 
+import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
+export const ScrollContainer = createAsyncComponent(() => import('./src/ScrollContainer.vue'));
+export const CollapseContainer = createAsyncComponent(
+  () => import('./src/collapse/CollapseContainer.vue')
+);
+export const LazyContainer = createAsyncComponent(() => import('./src/LazyContainer.vue'));
+
 withInstall(ScrollContainer, CollapseContainer, LazyContainer);
 
 export * from './src/types';
-
-export { ScrollContainer, CollapseContainer, LazyContainer };

+ 3 - 2
src/components/CountTo/index.ts

@@ -1,7 +1,8 @@
 // Transform vue-count-to to support vue3 version
 
-import CountTo from './src/index.vue';
 import { withInstall } from '../util';
 
+import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
+export const CountTo = createAsyncComponent(() => import('./src/index.vue'));
+
 withInstall(CountTo);
-export { CountTo };

+ 3 - 3
src/components/Description/index.ts

@@ -1,9 +1,9 @@
-import Description from './src/index';
-
 import { withInstall } from '../util';
 
+import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
+export const Description = createAsyncComponent(() => import('./src/index'));
+
 withInstall(Description);
 
 export * from './src/types';
 export { useDescription } from './src/useDescription';
-export { Description };

+ 3 - 2
src/components/Drawer/index.ts

@@ -1,7 +1,8 @@
-import BasicDrawer from './src/BasicDrawer';
 import { withInstall } from '../util';
 
+import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
+export const BasicDrawer = createAsyncComponent(() => import('./src/BasicDrawer'));
+
 withInstall(BasicDrawer);
 export * from './src/types';
 export { useDrawer, useDrawerInner } from './src/useDrawer';
-export { BasicDrawer };

+ 3 - 3
src/components/Dropdown/index.ts

@@ -1,7 +1,7 @@
-import Dropdown from './src/Dropdown';
 import { withInstall } from '../util';
 
+import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
+export const Dropdown = createAsyncComponent(() => import('./src/Dropdown'));
+
 withInstall(Dropdown);
 export * from './src/types';
-
-export { Dropdown };

+ 5 - 5
src/components/Excel/index.ts

@@ -1,12 +1,12 @@
-import ImportExcel from './src/ImportExcel.vue';
-import ExportExcelModel from './src/ExportExcelModel.vue';
+import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
 
 import { withInstall } from '../util';
 
-withInstall(ImportExcel, ExportExcelModel);
+export const ImpExcel = createAsyncComponent(() => import('./src/ImportExcel.vue'));
+export const ExpExcelModel = createAsyncComponent(() => import('./src/ExportExcelModel.vue'));
+
+withInstall(ImpExcel, ExpExcelModel);
 
 export * from './src/types';
 
 export { jsonToSheetXlsx, aoaToSheetXlsx } from './src/Export2Excel';
-
-export { ImportExcel, ExportExcelModel };

+ 9 - 1
src/components/Icon/index.tsx

@@ -1,5 +1,7 @@
 import './index.less';
 
+import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
+
 import type { PropType } from 'vue';
 import {
   defineComponent,
@@ -14,7 +16,7 @@ import {
 import Iconify from '@purge-icons/generated';
 import { isString } from '/@/utils/is';
 import { propTypes } from '/@/utils/propTypes';
-export default defineComponent({
+const Icon = defineComponent({
   name: 'GIcon',
   props: {
     // icon name
@@ -81,3 +83,9 @@ export default defineComponent({
     );
   },
 });
+
+export default createAsyncComponent(() => {
+  return new Promise((resolve) => {
+    resolve(Icon);
+  });
+});

+ 3 - 3
src/components/Loading/index.ts

@@ -1,9 +1,9 @@
 import './src/indicator';
-import Loading from './src/index.vue';
 import { withInstall } from '../util';
 
+import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
+export const Loading = createAsyncComponent(() => import('./src/index.vue'));
+
 withInstall(Loading);
 export { useLoading } from './src/useLoading';
 export { createLoading } from './src/createLoading';
-
-export { Loading };

+ 3 - 4
src/components/Markdown/index.ts

@@ -1,9 +1,8 @@
-import MarkDown from './src/index.vue';
-
 import { withInstall } from '../util';
 
+import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
+export const MarkDown = createAsyncComponent(() => import('./src/index.vue'));
+
 withInstall(MarkDown);
 
 export * from './src/types';
-
-export { MarkDown };

+ 4 - 2
src/components/Menu/index.ts

@@ -1,5 +1,7 @@
-import BasicMenu from './src/BasicMenu';
 import { withInstall } from '../util';
 
+import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
+
+export const BasicMenu = createAsyncComponent(() => import('./src/BasicMenu'), { loading: false });
+
 withInstall(BasicMenu);
-export { BasicMenu };

+ 3 - 2
src/components/Modal/index.ts

@@ -1,10 +1,11 @@
 import './src/index.less';
-import BasicModal from './src/BasicModal';
 import { withInstall } from '../util';
+import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
+
+export const BasicModal = createAsyncComponent(() => import('./src/BasicModal'));
 
 withInstall(BasicModal);
 
 export { useModalContext } from './src/useModalContext';
 export { useModal, useModalInner } from './src/useModal';
 export * from './src/types';
-export { BasicModal };

+ 3 - 2
src/components/Page/index.ts

@@ -1,5 +1,6 @@
-import PageFooter from './src/PageFooter.vue';
 import { withInstall } from '../util';
 
+import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
+export const PageFooter = createAsyncComponent(() => import('./src/PageFooter.vue'));
+
 withInstall(PageFooter);
-export { PageFooter };

+ 6 - 1
src/components/Qrcode/index.ts

@@ -1,2 +1,7 @@
-export { default as QrCode } from './src/index.vue';
+import { withInstall } from '../util';
+
+import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
+export const QrCode = createAsyncComponent(() => import('./src/index.vue'));
+
+withInstall(QrCode);
 export * from './src/types';

+ 3 - 2
src/components/Scrollbar/index.ts

@@ -2,10 +2,11 @@
  * copy from element-ui
  */
 
-import Scrollbar from './src/Scrollbar';
 import { withInstall } from '../util';
 
+import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
+export const Scrollbar = createAsyncComponent(() => import('./src/Scrollbar'));
+
 withInstall(Scrollbar);
 
-export { Scrollbar };
 export type { ScrollbarType } from './src/types';

+ 4 - 2
src/components/StrengthMeter/index.tsx

@@ -1,5 +1,7 @@
-import StrengthMeter from './src/index';
 import { withInstall } from '../util';
 
+import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
+
+export const StrengthMeter = createAsyncComponent(() => import('./src/index'));
+
 withInstall(StrengthMeter);
-export { StrengthMeter };

+ 3 - 2
src/components/Tinymce/index.ts

@@ -1,5 +1,6 @@
-import Tinymce from './src/Editor.vue';
 import { withInstall } from '../util';
 
+import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
+export const Tinymce = createAsyncComponent(() => import('./src/Editor.vue'));
+
 withInstall(Tinymce);
-export { Tinymce };

+ 2 - 1
src/components/Transition/index.ts

@@ -1,4 +1,5 @@
 import { createSimpleTransition, createJavascriptTransition } from './src/CreateTransition';
+import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
 
 import ExpandTransitionGenerator from './src/ExpandTransition';
 
@@ -28,4 +29,4 @@ export const ExpandXTransition = createJavascriptTransition(
   ExpandTransitionGenerator('', true)
 );
 
-export { default as ExpandTransition } from './src/ExpandTransition.vue';
+export const ExpandTransition = createAsyncComponent(() => import('./src/ExpandTransition.vue'));

+ 8 - 2
src/components/Tree/index.ts

@@ -1,3 +1,9 @@
-export { default as BasicTree } from './src/BasicTree';
-export * from './src/types';
+import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
+import { withInstall } from '../util';
+
+export const BasicTree = createAsyncComponent(() => import('./src/BasicTree'));
+
+withInstall(BasicTree);
+
 export type { ContextMenuItem } from '/@/hooks/web/useContextMenu';
+export * from './src/types';

+ 3 - 2
src/components/Upload/index.ts

@@ -1,5 +1,6 @@
-import BasicUpload from './src/BasicUpload.vue';
 import { withInstall } from '../util';
 
+import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
+export const BasicUpload = createAsyncComponent(() => import('./src/BasicUpload.vue'));
+
 withInstall(BasicUpload);
-export { BasicUpload };

+ 5 - 4
src/components/Verify/index.ts

@@ -1,9 +1,10 @@
-import BasicDragVerify from './src/DragVerify';
-import RotateDragVerify from './src/ImgRotate';
 import { withInstall } from '../util';
 
+import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
+
+export const BasicDragVerify = createAsyncComponent(() => import('./src/DragVerify'));
+export const RotateDragVerify = createAsyncComponent(() => import('./src/ImgRotate'));
+
 withInstall(BasicDragVerify, RotateDragVerify);
 
 export * from './src/types';
-
-export { BasicDragVerify, RotateDragVerify };

+ 5 - 3
src/components/VirtualScroll/index.ts

@@ -1,5 +1,7 @@
-import VirtualScroll from './src/index';
 import { withInstall } from '../util';
 
-withInstall(VirtualScroll);
-export { VirtualScroll };
+import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
+
+export const VScroll = createAsyncComponent(() => import('./src/index'));
+
+withInstall(VScroll);

+ 3 - 0
src/design/ant/btn.less

@@ -1,5 +1,8 @@
 // button重置
 .ant-btn {
+  display: inline-flex;
+  justify-content: center;
+  align-items: center;
   // &.ant-btn-success:not(.ant-btn-link),
   // &.ant-btn-error:not(.ant-btn-link),
   // &.ant-btn-warning:not(.ant-btn-link),

+ 4 - 3
src/layouts/page/index.tsx

@@ -54,7 +54,10 @@ export default defineComponent({
                   renderComp()
                 );
 
-                return unref(getEnableTransition) ? (
+                if (!unref(getEnableTransition)) {
+                  return PageContent;
+                }
+                return (
                   <Transition
                     name={name || route.meta.transitionName || unref(getBasicTransition)}
                     mode="out-in"
@@ -62,8 +65,6 @@ export default defineComponent({
                   >
                     {() => PageContent}
                   </Transition>
-                ) : (
-                  PageContent
                 );
               },
             }}

+ 20 - 2
src/utils/factory/createAsyncComponent.tsx

@@ -1,6 +1,24 @@
-import { defineAsyncComponent } from 'vue';
+import {
+  defineAsyncComponent,
+  // FunctionalComponent, CSSProperties
+} from 'vue';
 import { Spin } from 'ant-design-vue';
 import { noop } from '/@/utils/index';
+
+// const Loading: FunctionalComponent<{ size: 'small' | 'default' | 'large' }> = (props) => {
+//   const style: CSSProperties = {
+//     position: 'absolute',
+//     display: 'flex',
+//     justifyContent: 'center',
+//     alignItems: 'center',
+//   };
+//   return (
+//     <div style={style}>
+//       <Spin spinning={true} size={props.size} />
+//     </div>
+//   );
+// };
+
 interface Options {
   size?: 'default' | 'small' | 'large';
   delay?: number;
@@ -10,7 +28,7 @@ interface Options {
 }
 
 export function createAsyncComponent(loader: Fn, options: Options = {}) {
-  const { size = 'small', delay = 100, timeout = 3000, loading = true, retry = true } = options;
+  const { size = 'small', delay = 100, timeout = 30000, loading = false, retry = true } = options;
   return defineAsyncComponent({
     loader,
     loadingComponent: loading ? <Spin spinning={true} size={size} /> : undefined,

+ 5 - 6
src/utils/http/axios/index.ts

@@ -106,7 +106,7 @@ const transform: AxiosTransform = {
     if (apiUrl && isString(apiUrl)) {
       config.url = `${apiUrl}${config.url}`;
     }
-    if (config.method === RequestEnum.GET) {
+    if (config.method?.toUpperCase() === RequestEnum.GET) {
       const now = new Date().getTime();
       if (!isString(config.params)) {
         config.data = {
@@ -157,14 +157,13 @@ const transform: AxiosTransform = {
     const { t } = useI18n();
     errorStore.setupErrorHandle(error);
     const { response, code, message } = error || {};
-    const msg: string =
-      response && response.data && response.data.error ? response.data.error.message : '';
-    const err: string = error.toString();
+    const msg: string = response?.data?.error ? response.data.error.message : '';
+    const err: string = error?.toString();
     try {
       if (code === 'ECONNABORTED' && message.indexOf('timeout') !== -1) {
         createMessage.error(t('sys.api.apiTimeoutMessage'));
       }
-      if (err && err.includes('Network Error')) {
+      if (err?.includes('Network Error')) {
         createErrorModal({
           title: t('sys.api.networkException'),
           content: t('sys.api.networkExceptionMsg'),
@@ -173,7 +172,7 @@ const transform: AxiosTransform = {
     } catch (error) {
       throw new Error(error);
     }
-    checkStatus(error.response && error.response.status, msg);
+    checkStatus(error?.response?.status, msg);
     return Promise.reject(error);
   },
 };

+ 1 - 1
src/views/demo/comp/button/index.vue

@@ -49,7 +49,7 @@
 
     <div class="my-2">
       <h3>primary</h3>
-      <a-button type="primary">主按钮</a-button>
+      <a-button type="primary" preIcon="mdi:page-next-outline">主按钮</a-button>
       <a-button type="primary" class="ml-2" disabled> 禁用 </a-button>
       <a-button type="primary" class="ml-2" loading> loading </a-button>
       <a-button type="link" class="ml-2"> link </a-button>

+ 6 - 6
src/views/demo/comp/scroll/VirtualScroll.vue

@@ -2,26 +2,26 @@
   <div class="p-4 virtual-scroll-demo">
     <Divider>基础滚动示例</Divider>
     <div class="virtual-scroll-demo-wrap">
-      <VirtualScroll :itemHeight="41" :items="data" :height="300" :width="300">
+      <VScroll :itemHeight="41" :items="data" :height="300" :width="300">
         <template v-slot="{ item }">
           <div class="virtual-scroll-demo__item">{{ item.title }}</div>
         </template>
-      </VirtualScroll>
+      </VScroll>
     </div>
 
     <Divider>即使不可见,也预先加载50条数据,防止空白</Divider>
     <div class="virtual-scroll-demo-wrap">
-      <VirtualScroll :itemHeight="41" :items="data" :height="300" :width="300" :bench="50">
+      <VScroll :itemHeight="41" :items="data" :height="300" :width="300" :bench="50">
         <template v-slot="{ item }">
           <div class="virtual-scroll-demo__item">{{ item.title }}</div>
         </template>
-      </VirtualScroll>
+      </VScroll>
     </div>
   </div>
 </template>
 <script lang="ts">
   import { defineComponent } from 'vue';
-  import { VirtualScroll } from '/@/components/VirtualScroll/index';
+  import { VScroll } from '/@/components/VirtualScroll/index';
 
   import { Divider } from 'ant-design-vue';
   const data: any[] = (() => {
@@ -34,7 +34,7 @@
     return arr;
   })();
   export default defineComponent({
-    components: { VirtualScroll, Divider },
+    components: { VScroll: VScroll, Divider },
     setup() {
       return { data: data };
     },

+ 5 - 5
src/views/demo/comp/verify/index.vue

@@ -2,12 +2,12 @@
   <div class="p-10">
     <div class="flex justify-center p-4 items-center bg-gray-700">
       <BasicDragVerify ref="el1" @success="handleSuccess" />
-      <a-button color="primary" class="ml-2" @click="handleBtnClick(el1)">还原</a-button>
+      <a-button type="primary" class="ml-2" @click="handleBtnClick(el1)">还原</a-button>
     </div>
 
     <div class="flex justify-center p-4 items-center bg-gray-700">
       <BasicDragVerify ref="el2" @success="handleSuccess" circle />
-      <a-button color="primary" class="ml-2" @click="handleBtnClick(el2)">还原</a-button>
+      <a-button type="primary" class="ml-2" @click="handleBtnClick(el2)">还原</a-button>
     </div>
 
     <div class="flex justify-center p-4 items-center bg-gray-700">
@@ -20,7 +20,7 @@
           background: '#018ffb',
         }"
       />
-      <a-button color="primary" class="ml-2" @click="handleBtnClick(el3)">还原</a-button>
+      <a-button type="primary" class="ml-2" @click="handleBtnClick(el3)">还原</a-button>
     </div>
 
     <div class="flex justify-center p-4 items-center bg-gray-700">
@@ -30,7 +30,7 @@
           <RightOutlined v-else />
         </template>
       </BasicDragVerify>
-      <a-button color="primary" class="ml-2" @click="handleBtnClick(el4)">还原</a-button>
+      <a-button type="primary" class="ml-2" @click="handleBtnClick(el4)">还原</a-button>
     </div>
 
     <div class="flex justify-center p-4 items-center bg-gray-700">
@@ -46,7 +46,7 @@
           </div>
         </template>
       </BasicDragVerify>
-      <a-button color="primary" class="ml-2" @click="handleBtnClick(el5)">还原</a-button>
+      <a-button type="primary" class="ml-2" @click="handleBtnClick(el5)">还原</a-button>
     </div>
   </div>
 </template>

+ 3 - 3
src/views/demo/excel/CustomExport.vue

@@ -5,19 +5,19 @@
         <a-button @click="openModal">导出</a-button>
       </template>
     </BasicTable>
-    <ExportExcelModel @register="register" @success="defaultHeader" />
+    <ExpExcelModel @register="register" @success="defaultHeader" />
   </div>
 </template>
 
 <script lang="ts">
   import { defineComponent } from 'vue';
   import { BasicTable } from '/@/components/Table';
-  import { jsonToSheetXlsx, ExportExcelModel, ExportModalResult } from '/@/components/Excel';
+  import { jsonToSheetXlsx, ExpExcelModel, ExportModalResult } from '/@/components/Excel';
   import { columns, data } from './data';
   import { useModal } from '/@/components/Modal';
 
   export default defineComponent({
-    components: { BasicTable, ExportExcelModel },
+    components: { BasicTable, ExpExcelModel },
     setup() {
       function defaultHeader({ filename, bookType }: ExportModalResult) {
         // 默认Object.keys(data[0])作为header

+ 4 - 4
src/views/demo/excel/ImportExcel.vue

@@ -1,8 +1,8 @@
 <template>
   <div class="m-4">
-    <ImportExcel @success="loadDataSuccess">
+    <ImpExcel @success="loadDataSuccess">
       <a-button class="m-3">导入Excel</a-button>
-    </ImportExcel>
+    </ImpExcel>
     <BasicTable
       v-for="(table, index) in tableListRef"
       :key="index"
@@ -15,11 +15,11 @@
 <script lang="ts">
   import { defineComponent, ref } from 'vue';
 
-  import { ImportExcel, ExcelData } from '/@/components/Excel';
+  import { ImpExcel, ExcelData } from '/@/components/Excel';
   import { BasicTable, BasicColumn } from '/@/components/Table';
 
   export default defineComponent({
-    components: { BasicTable, ImportExcel },
+    components: { BasicTable, ImpExcel },
 
     setup() {
       const tableListRef = ref<