Commit 0f4b847d69e90e5bbb4fb0883fb5ea1dd1daf1e7

Authored by vben
1 parent e79e540b

perf(lazy-container): optimize lazyContainer code

.browserslistrc deleted 100644 → 0
1   -> 1%
2   -last 2 versions
3   -not ie <= 10
CHANGELOG.zh_CN.md
... ... @@ -2,7 +2,8 @@
2 2  
3 3 ### ⚡ Performance Improvements
4 4  
5   -- 菜单性能继续优化
  5 +- 菜单性能继续优化,更流畅
  6 +- 优化懒加载组件及示例
6 7  
7 8 ### 🎫 Chores
8 9  
... ... @@ -13,6 +14,7 @@
13 14 ### 🐛 Bug Fixes
14 15  
15 16 - 修复升级之后 table 类型问题
  17 +- 修复分割菜单且左侧菜单没有数据时候,继续展示上一次子菜单的问题
16 18  
17 19 ## 2.0.0-rc.8 (2020-11-2)
18 20  
... ...
src/components/Container/src/LazyContainer.vue
1 1 <template>
2   - <transition-group v-bind="$attrs" ref="elRef" :name="transitionName" :tag="tag">
  2 + <transition-group
  3 + class="lazy-container"
  4 + v-bind="$attrs"
  5 + ref="elRef"
  6 + :name="transitionName"
  7 + :tag="tag"
  8 + mode="out-in"
  9 + >
3 10 <div key="component" v-if="isInit">
4 11 <slot :loading="loading" />
5 12 </div>
6   - <div key="skeleton">
  13 + <div key="skeleton" v-else name="lazy-skeleton">
7 14 <slot name="skeleton" v-if="$slots.skeleton" />
8 15 <Skeleton v-else />
9 16 </div>
... ... @@ -12,19 +19,9 @@
12 19 <script lang="ts">
13 20 import type { PropType } from 'vue';
14 21  
15   - import {
16   - defineComponent,
17   - reactive,
18   - onMounted,
19   - ref,
20   - unref,
21   - onUnmounted,
22   - toRef,
23   - toRefs,
24   - } from 'vue';
  22 + import { defineComponent, reactive, onMounted, ref, toRef, toRefs } from 'vue';
25 23  
26 24 import { Skeleton } from 'ant-design-vue';
27   - import { useRaf } from '/@/hooks/event/useRaf';
28 25 import { useTimeout } from '/@/hooks/core/useTimeout';
29 26 import { useIntersectionObserver } from '/@/hooks/event/useIntersectionObserver';
30 27 interface State {
... ... @@ -36,13 +33,12 @@
36 33 name: 'LazyContainer',
37 34 components: { Skeleton },
38 35 props: {
39   - // 等待时间,如果指定了时间,不论可见与否,在指定时间之后自动加载
  36 + // Waiting time, if the time is specified, whether visible or not, it will be automatically loaded after the specified time
40 37 timeout: {
41 38 type: Number as PropType<number>,
42   - default: 0,
43   - // default: 8000,
44 39 },
45   - // 组件所在的视口,如果组件是在页面容器内滚动,视口就是该容器
  40 +
  41 + // The viewport where the component is located. If the component is scrolling in the page container, the viewport is the container
46 42 viewport: {
47 43 type: (typeof window !== 'undefined' ? window.HTMLElement : Object) as PropType<
48 44 HTMLElement
... ... @@ -50,19 +46,19 @@
50 46 default: () => null,
51 47 },
52 48  
53   - // 预加载阈值, css单位
  49 + // Preload threshold, css unit
54 50 threshold: {
55 51 type: String as PropType<string>,
56 52 default: '0px',
57 53 },
58 54  
59   - // 视口的滚动方向, vertical代表垂直方向,horizontal代表水平方向
  55 + // The scroll direction of the viewport, vertical represents the vertical direction, horizontal represents the horizontal direction
60 56 direction: {
61 57 type: String as PropType<'vertical' | 'horizontal'>,
62 58 default: 'vertical',
63 59 },
64 60  
65   - // 包裹组件的外层容器的标签名
  61 + // The label name of the outer container that wraps the component
66 62 tag: {
67 63 type: String as PropType<string>,
68 64 default: 'div',
... ... @@ -105,23 +101,11 @@
105 101 function init() {
106 102 state.loading = true;
107 103  
108   - requestAnimationFrameFn(() => {
109   - state.isInit = true;
110   - emit('init');
111   - });
112   - }
113   -
114   - function requestAnimationFrameFn(callback: () => any) {
115   - // Prevent waiting too long without executing the callback
116   - // Set the maximum waiting time
117 104 useTimeout(() => {
118 105 if (state.isInit) return;
119   - callback();
  106 + state.isInit = true;
  107 + emit('init');
120 108 }, props.maxWaitingTime || 80);
121   -
122   - const { requestAnimationFrame } = useRaf();
123   -
124   - return requestAnimationFrame;
125 109 }
126 110  
127 111 function initIntersectionObserver() {
... ... @@ -165,31 +149,8 @@
165 149 });
166 150 </script>
167 151 <style lang="less">
168   - .lazy-container-enter {
169   - opacity: 0;
170   - }
171   -
172   - .lazy-container-enter-to {
173   - opacity: 1;
174   - }
175   -
176   - .lazy-container-enter-from,
177   - .lazy-container-enter-active {
178   - position: absolute;
179   - top: 0;
  152 + .lazy-container {
180 153 width: 100%;
181   - transition: opacity 0.3s 0.2s;
182   - }
183   -
184   - .lazy-container-leave {
185   - opacity: 1;
186   - }
187   -
188   - .lazy-container-leave-to {
189   - opacity: 0;
190   - }
191   -
192   - .lazy-container-leave-active {
193   - transition: opacity 0.5s;
  154 + height: 100%;
194 155 }
195 156 </style>
... ...
src/components/Container/src/collapse/CollapseContainer.vue
... ... @@ -8,13 +8,13 @@
8 8 <CollapseTransition :enable="canExpan">
9 9 <Skeleton v-if="loading" />
10 10 <div class="collapse-container__body" v-else v-show="show">
11   - <!-- <LazyContainer :timeout="lazyTime" v-if="lazy">
  11 + <LazyContainer :timeout="lazyTime" v-if="lazy">
12 12 <slot />
13 13 <template #skeleton>
14 14 <slot name="lazySkeleton" />
15 15 </template>
16   - </LazyContainer> -->
17   - <slot />
  16 + </LazyContainer>
  17 + <slot v-else />
18 18 </div>
19 19 </CollapseTransition>
20 20 </div>
... ... @@ -28,7 +28,7 @@
28 28 import CollapseHeader from './CollapseHeader.vue';
29 29 import { Skeleton } from 'ant-design-vue';
30 30  
31   - // import LazyContainer from '../LazyContainer';
  31 + import LazyContainer from '../LazyContainer.vue';
32 32  
33 33 import { triggerWindowResize } from '/@/utils/event/triggerWindowResizeEvent';
34 34 // hook
... ... @@ -36,7 +36,7 @@
36 36 export default defineComponent({
37 37 components: {
38 38 Skeleton,
39   - // LazyContainer,
  39 + LazyContainer,
40 40 CollapseHeader,
41 41 CollapseTransition,
42 42 },
... ... @@ -75,7 +75,7 @@
75 75 // 延时加载时间
76 76 lazyTime: {
77 77 type: Number as PropType<number>,
78   - default: 3000,
  78 + default: 0,
79 79 },
80 80 },
81 81 setup(props) {
... ...
src/components/ContextMenu/src/index.tsx
... ... @@ -25,11 +25,13 @@ export default defineComponent({
25 25 const state = reactive({
26 26 show: false,
27 27 });
  28 +
28 29 onMounted(() => {
29 30 nextTick(() => {
30 31 state.show = true;
31 32 });
32 33 });
  34 +
33 35 onUnmounted(() => {
34 36 const el = unref(wrapRef);
35 37 el && document.body.removeChild(el);
... ... @@ -61,6 +63,7 @@ export default defineComponent({
61 63  
62 64 handler && handler();
63 65 }
  66 +
64 67 function renderContent(item: ContextMenuItem) {
65 68 const { icon, label } = item;
66 69  
... ... @@ -72,6 +75,7 @@ export default defineComponent({
72 75 </span>
73 76 );
74 77 }
  78 +
75 79 function renderMenuItem(items: ContextMenuItem[]) {
76 80 return items.map((item, index) => {
77 81 const { disabled, label, children, divider = false } = item;
... ...
src/components/Preview/src/index.tsx
... ... @@ -265,6 +265,7 @@ export default defineComponent({
265 265 </div>
266 266 );
267 267 };
  268 +
268 269 return () => {
269 270 return (
270 271 imgState.show && (
... ...
src/router/menus/modules/demo/comp.ts
... ... @@ -19,6 +19,26 @@ const menu: MenuModule = {
19 19 },
20 20  
21 21 {
  22 + path: 'modal',
  23 + name: '弹窗扩展',
  24 + },
  25 + {
  26 + path: 'drawer',
  27 + name: '抽屉扩展',
  28 + },
  29 + {
  30 + path: 'desc',
  31 + name: '详情组件',
  32 + },
  33 + {
  34 + path: 'qrcode',
  35 + name: '二维码组件',
  36 + },
  37 + {
  38 + path: 'strength-meter',
  39 + name: '密码强度组件',
  40 + },
  41 + {
22 42 path: 'scroll',
23 43 name: '滚动组件',
24 44 children: [
... ... @@ -37,20 +57,18 @@ const menu: MenuModule = {
37 57 ],
38 58 },
39 59 {
40   - path: 'modal',
41   - name: '弹窗扩展',
42   - },
43   - {
44   - path: 'drawer',
45   - name: '抽屉扩展',
46   - },
47   - {
48   - path: 'desc',
49   - name: '详情组件',
50   - },
51   - {
52 60 path: 'lazy',
53 61 name: '懒加载组件',
  62 + children: [
  63 + {
  64 + path: 'basic',
  65 + name: '基础示例',
  66 + },
  67 + {
  68 + path: 'transition',
  69 + name: '动画效果',
  70 + },
  71 + ],
54 72 },
55 73 {
56 74 path: 'verify',
... ... @@ -66,14 +84,6 @@ const menu: MenuModule = {
66 84 },
67 85 ],
68 86 },
69   - {
70   - path: 'qrcode',
71   - name: '二维码组件',
72   - },
73   - {
74   - path: 'strength-meter',
75   - name: '密码强度组件',
76   - },
77 87 ],
78 88 },
79 89 };
... ...
src/router/routes/modules/demo/comp.ts
... ... @@ -99,13 +99,32 @@ export default {
99 99 title: '详情组件',
100 100 },
101 101 },
  102 +
102 103 {
103 104 path: '/lazy',
104 105 name: 'lazyDemo',
105   - component: () => import('/@/views/demo/comp/lazy/index.vue'),
  106 + redirect: '/comp/lazy/basic',
106 107 meta: {
107 108 title: '懒加载组件',
108 109 },
  110 + children: [
  111 + {
  112 + path: 'basic',
  113 + name: 'BasicLazyDemo',
  114 + component: () => import('/@/views/demo/comp/lazy/index.vue'),
  115 + meta: {
  116 + title: '基础示例',
  117 + },
  118 + },
  119 + {
  120 + path: 'transition',
  121 + name: 'BasicTransitionDemo',
  122 + component: () => import('/@/views/demo/comp/lazy/Transition.vue'),
  123 + meta: {
  124 + title: '动画效果',
  125 + },
  126 + },
  127 + ],
109 128 },
110 129 {
111 130 path: '/verify',
... ...
src/views/demo/comp/lazy/Transition.vue 0 → 100644
  1 +<template>
  2 + <div class="p-4 lazy-base-demo">
  3 + <Alert message="自定义动画" description="懒加载组件显示动画" type="info" show-icon />
  4 + <div class="lazy-base-demo-wrap">
  5 + <h1>向下滚动</h1>
  6 +
  7 + <div class="lazy-base-demo-box">
  8 + <LazyContainer transitionName="custom">
  9 + <TargetContent />
  10 + </LazyContainer>
  11 + </div>
  12 + </div>
  13 + </div>
  14 +</template>
  15 +<script lang="ts">
  16 + import { defineComponent } from 'vue';
  17 + import { Skeleton, Alert } from 'ant-design-vue';
  18 + import TargetContent from './TargetContent.vue';
  19 + import { LazyContainer } from '/@/components/Container/index';
  20 + export default defineComponent({
  21 + components: { LazyContainer, TargetContent, Skeleton, Alert },
  22 + setup() {
  23 + return {};
  24 + },
  25 + });
  26 +</script>
  27 +<style lang="less">
  28 + .lazy-base-demo {
  29 + &-wrap {
  30 + display: flex;
  31 + width: 50%;
  32 + height: 2000px;
  33 + margin: 20px auto;
  34 + text-align: center;
  35 + background: #fff;
  36 + justify-content: center;
  37 + flex-direction: column;
  38 + align-items: center;
  39 + }
  40 +
  41 + &-box {
  42 + width: 300px;
  43 + height: 300px;
  44 + }
  45 +
  46 + h1 {
  47 + height: 1300px;
  48 + margin: 20px 0;
  49 + }
  50 + }
  51 +
  52 + .custom-enter {
  53 + opacity: 0;
  54 + transform: scale(0.4) translate(100%);
  55 + }
  56 +
  57 + .custom-enter-to {
  58 + opacity: 1;
  59 + }
  60 +
  61 + .custom-enter-active {
  62 + position: absolute;
  63 + top: 0;
  64 + width: 100%;
  65 + transition: all 0.5s;
  66 + }
  67 +
  68 + .custom-leave {
  69 + opacity: 1;
  70 + }
  71 +
  72 + .custom-leave-to {
  73 + opacity: 0;
  74 + transform: scale(0.4) translate(-100%);
  75 + }
  76 +
  77 + .custom-leave-active {
  78 + transition: all 0.5s;
  79 + }
  80 +</style>
... ...
src/views/demo/comp/lazy/index.vue
... ... @@ -3,12 +3,15 @@
3 3 <Alert message="基础示例" description="向下滚动到可见区域才会加载组件" type="info" show-icon />
4 4 <div class="lazy-base-demo-wrap">
5 5 <h1>向下滚动</h1>
6   - <LazyContainer @init="() => {}">
7   - <TargetContent />
8   - <template #skeleton>
9   - <Skeleton :rows="10" />
10   - </template>
11   - </LazyContainer>
  6 +
  7 + <div class="lazy-base-demo-box">
  8 + <LazyContainer>
  9 + <TargetContent />
  10 + <template #skeleton>
  11 + <Skeleton :rows="10" />
  12 + </template>
  13 + </LazyContainer>
  14 + </div>
12 15 </div>
13 16 </div>
14 17 </template>
... ... @@ -24,7 +27,7 @@
24 27 },
25 28 });
26 29 </script>
27   -<style lang="less" scoped>
  30 +<style lang="less">
28 31 .lazy-base-demo {
29 32 &-wrap {
30 33 display: flex;
... ... @@ -38,6 +41,11 @@
38 41 align-items: center;
39 42 }
40 43  
  44 + &-box {
  45 + width: 300px;
  46 + height: 300px;
  47 + }
  48 +
41 49 h1 {
42 50 height: 1300px;
43 51 margin: 20px 0;
... ...