Commit 6a9bd686d5e7d3928f39856da4e9e3920ac5cbee
1 parent
6890dd72
chore: remove LazyContainer
Showing
11 changed files
with
2 additions
and
382 deletions
packages/hooks/src/useRefs.ts
1 | 1 | import type { Ref } from 'vue'; |
2 | -import { onBeforeUpdate, ref } from 'vue'; | |
2 | +import { onBeforeUpdate, shallowRef } from 'vue'; | |
3 | 3 | |
4 | 4 | export function useRefs(): [Ref<HTMLElement[]>, (index: number) => (el: HTMLElement) => void] { |
5 | - const refs = ref([]) as Ref<HTMLElement[]>; | |
5 | + const refs = shallowRef([]) as Ref<HTMLElement[]>; | |
6 | 6 | |
7 | 7 | onBeforeUpdate(() => { |
8 | 8 | refs.value = []; | ... | ... |
src/components/Container/index.ts
1 | 1 | import { withInstall } from '/@/utils'; |
2 | 2 | import collapseContainer from './src/collapse/CollapseContainer.vue'; |
3 | 3 | import scrollContainer from './src/ScrollContainer.vue'; |
4 | -import lazyContainer from './src/LazyContainer.vue'; | |
5 | 4 | |
6 | 5 | export const CollapseContainer = withInstall(collapseContainer); |
7 | 6 | export const ScrollContainer = withInstall(scrollContainer); |
8 | -export const LazyContainer = withInstall(lazyContainer); | |
9 | 7 | |
10 | 8 | export * from './src/typing'; | ... | ... |
src/components/Container/src/LazyContainer.vue deleted
100644 → 0
1 | -<template> | |
2 | - <transition-group | |
3 | - class="h-full w-full" | |
4 | - v-bind="$attrs" | |
5 | - ref="elRef" | |
6 | - :name="transitionName" | |
7 | - :tag="tag" | |
8 | - mode="out-in" | |
9 | - > | |
10 | - <div key="component" v-if="isInit"> | |
11 | - <slot :loading="loading"></slot> | |
12 | - </div> | |
13 | - <div key="skeleton" v-else> | |
14 | - <slot name="skeleton" v-if="$slots.skeleton"></slot> | |
15 | - <Skeleton v-else /> | |
16 | - </div> | |
17 | - </transition-group> | |
18 | -</template> | |
19 | -<script lang="ts"> | |
20 | - import type { PropType } from 'vue'; | |
21 | - import { defineComponent, reactive, onMounted, ref, toRef, toRefs } from 'vue'; | |
22 | - import { useTimeoutFn } from '@vben/hooks'; | |
23 | - import { Skeleton } from 'ant-design-vue'; | |
24 | - import { useIntersectionObserver } from '/@/hooks/event/useIntersectionObserver'; | |
25 | - | |
26 | - interface State { | |
27 | - isInit: boolean; | |
28 | - loading: boolean; | |
29 | - intersectionObserverInstance: IntersectionObserver | null; | |
30 | - } | |
31 | - | |
32 | - const props = { | |
33 | - /** | |
34 | - * Waiting time, if the time is specified, whether visible or not, it will be automatically loaded after the specified time | |
35 | - */ | |
36 | - timeout: { type: Number }, | |
37 | - /** | |
38 | - * The viewport where the component is located. | |
39 | - * If the component is scrolling in the page container, the viewport is the container | |
40 | - */ | |
41 | - viewport: { | |
42 | - type: (typeof window !== 'undefined' ? window.HTMLElement : Object) as PropType<HTMLElement>, | |
43 | - default: () => null, | |
44 | - }, | |
45 | - /** | |
46 | - * Preload threshold, css unit | |
47 | - */ | |
48 | - threshold: { type: String, default: '0px' }, | |
49 | - /** | |
50 | - * The scroll direction of the viewport, vertical represents the vertical direction, horizontal represents the horizontal direction | |
51 | - */ | |
52 | - direction: { | |
53 | - type: String, | |
54 | - default: 'vertical', | |
55 | - validator: (v) => ['vertical', 'horizontal'].includes(v), | |
56 | - }, | |
57 | - /** | |
58 | - * The label name of the outer container that wraps the component | |
59 | - */ | |
60 | - tag: { type: String, default: 'div' }, | |
61 | - maxWaitingTime: { type: Number, default: 80 }, | |
62 | - /** | |
63 | - * transition name | |
64 | - */ | |
65 | - transitionName: { type: String, default: 'lazy-container' }, | |
66 | - }; | |
67 | - | |
68 | - export default defineComponent({ | |
69 | - name: 'LazyContainer', | |
70 | - components: { Skeleton }, | |
71 | - inheritAttrs: false, | |
72 | - props, | |
73 | - emits: ['init'], | |
74 | - setup(props, { emit }) { | |
75 | - const elRef = ref(); | |
76 | - const state = reactive<State>({ | |
77 | - isInit: false, | |
78 | - loading: false, | |
79 | - intersectionObserverInstance: null, | |
80 | - }); | |
81 | - | |
82 | - onMounted(() => { | |
83 | - immediateInit(); | |
84 | - initIntersectionObserver(); | |
85 | - }); | |
86 | - | |
87 | - // If there is a set delay time, it will be executed immediately | |
88 | - function immediateInit() { | |
89 | - const { timeout } = props; | |
90 | - timeout && | |
91 | - useTimeoutFn(() => { | |
92 | - init(); | |
93 | - }, timeout); | |
94 | - } | |
95 | - | |
96 | - function init() { | |
97 | - state.loading = true; | |
98 | - | |
99 | - useTimeoutFn(() => { | |
100 | - if (state.isInit) return; | |
101 | - state.isInit = true; | |
102 | - emit('init'); | |
103 | - }, props.maxWaitingTime || 80); | |
104 | - } | |
105 | - | |
106 | - function initIntersectionObserver() { | |
107 | - const { timeout, direction, threshold } = props; | |
108 | - if (timeout) return; | |
109 | - // According to the scrolling direction to construct the viewport margin, used to load in advance | |
110 | - let rootMargin = '0px'; | |
111 | - switch (direction) { | |
112 | - case 'vertical': | |
113 | - rootMargin = `${threshold} 0px`; | |
114 | - break; | |
115 | - case 'horizontal': | |
116 | - rootMargin = `0px ${threshold}`; | |
117 | - break; | |
118 | - } | |
119 | - | |
120 | - try { | |
121 | - const { stop, observer } = useIntersectionObserver({ | |
122 | - rootMargin, | |
123 | - target: toRef(elRef.value, '$el'), | |
124 | - onIntersect: (entries: any[]) => { | |
125 | - const isIntersecting = entries[0].isIntersecting || entries[0].intersectionRatio; | |
126 | - if (isIntersecting) { | |
127 | - init(); | |
128 | - if (observer) { | |
129 | - stop(); | |
130 | - } | |
131 | - } | |
132 | - }, | |
133 | - root: toRef(props, 'viewport'), | |
134 | - }); | |
135 | - } catch (e) { | |
136 | - init(); | |
137 | - } | |
138 | - } | |
139 | - return { | |
140 | - elRef, | |
141 | - ...toRefs(state), | |
142 | - }; | |
143 | - }, | |
144 | - }); | |
145 | -</script> |
src/hooks/event/useIntersectionObserver.ts deleted
100644 → 0
1 | -import { Ref, watchEffect, ref } from 'vue'; | |
2 | - | |
3 | -interface IntersectionObserverProps { | |
4 | - target: Ref<Element | null | undefined>; | |
5 | - root?: Ref<any>; | |
6 | - onIntersect: IntersectionObserverCallback; | |
7 | - rootMargin?: string; | |
8 | - threshold?: number; | |
9 | -} | |
10 | - | |
11 | -export function useIntersectionObserver({ | |
12 | - target, | |
13 | - root, | |
14 | - onIntersect, | |
15 | - rootMargin = '0px', | |
16 | - threshold = 0.1, | |
17 | -}: IntersectionObserverProps) { | |
18 | - let cleanup = () => {}; | |
19 | - const observer: Ref<Nullable<IntersectionObserver>> = ref(null); | |
20 | - const stopEffect = watchEffect(() => { | |
21 | - cleanup(); | |
22 | - | |
23 | - observer.value = new IntersectionObserver(onIntersect, { | |
24 | - root: root ? root.value : null, | |
25 | - rootMargin, | |
26 | - threshold, | |
27 | - }); | |
28 | - | |
29 | - const current = target.value; | |
30 | - | |
31 | - current && observer.value.observe(current); | |
32 | - | |
33 | - cleanup = () => { | |
34 | - if (observer.value) { | |
35 | - observer.value.disconnect(); | |
36 | - target.value && observer.value.unobserve(target.value); | |
37 | - } | |
38 | - }; | |
39 | - }); | |
40 | - | |
41 | - return { | |
42 | - observer, | |
43 | - stop: () => { | |
44 | - cleanup(); | |
45 | - stopEffect(); | |
46 | - }, | |
47 | - }; | |
48 | -} |
src/hooks/web/useMessage.tsx
1 | 1 | import type { ModalFunc, ModalFuncProps } from 'ant-design-vue/lib/modal/Modal'; |
2 | - | |
3 | 2 | import { Modal, message as Message, notification } from 'ant-design-vue'; |
4 | 3 | import { InfoCircleFilled, CheckCircleFilled, CloseCircleFilled } from '@ant-design/icons-vue'; |
5 | - | |
6 | 4 | import { NotificationArgsProps, ConfigProps } from 'ant-design-vue/lib/notification'; |
7 | 5 | import { useI18n } from './useI18n'; |
8 | 6 | import { isString } from '/@/utils/is'; | ... | ... |
src/locales/lang/en/routes/demo.ts
src/locales/lang/zh-CN/routes/demo.ts
src/router/routes/modules/demo/comp.ts
... | ... | @@ -471,33 +471,6 @@ const comp: AppRouteModule = { |
471 | 471 | }, |
472 | 472 | |
473 | 473 | { |
474 | - path: 'lazy', | |
475 | - name: 'LazyDemo', | |
476 | - component: getParentLayout('LazyDemo'), | |
477 | - redirect: '/comp/lazy/basic', | |
478 | - meta: { | |
479 | - title: t('routes.demo.comp.lazy'), | |
480 | - }, | |
481 | - children: [ | |
482 | - { | |
483 | - path: 'basic', | |
484 | - name: 'BasicLazyDemo', | |
485 | - component: () => import('/@/views/demo/comp/lazy/index.vue'), | |
486 | - meta: { | |
487 | - title: t('routes.demo.comp.lazyBasic'), | |
488 | - }, | |
489 | - }, | |
490 | - { | |
491 | - path: 'transition', | |
492 | - name: 'BasicTransitionDemo', | |
493 | - component: () => import('/@/views/demo/comp/lazy/Transition.vue'), | |
494 | - meta: { | |
495 | - title: t('routes.demo.comp.lazyTransition'), | |
496 | - }, | |
497 | - }, | |
498 | - ], | |
499 | - }, | |
500 | - { | |
501 | 474 | path: 'verify', |
502 | 475 | name: 'VerifyDemo', |
503 | 476 | component: getParentLayout('VerifyDemo'), | ... | ... |
src/views/demo/comp/lazy/TargetContent.vue deleted
100644 → 0
1 | -<template> | |
2 | - <Card hoverable :style="{ width: '240px', background: '#fff' }"> | |
3 | - <template #cover> | |
4 | - <img alt="example" src="https://os.alipayobjects.com/rmsportal/QBnOOoLaAfKPirc.png" /> | |
5 | - </template> | |
6 | - <CardMeta title="懒加载组件" /> | |
7 | - </Card> | |
8 | -</template> | |
9 | -<script lang="ts"> | |
10 | - import { defineComponent } from 'vue'; | |
11 | - import { Card } from 'ant-design-vue'; | |
12 | - | |
13 | - export default defineComponent({ | |
14 | - components: { CardMeta: Card.Meta, Card }, | |
15 | - setup() { | |
16 | - return {}; | |
17 | - }, | |
18 | - }); | |
19 | -</script> |
src/views/demo/comp/lazy/Transition.vue deleted
100644 → 0
1 | -<template> | |
2 | - <PageWrapper title="懒加载自定义动画示例" content="懒加载组件显示动画"> | |
3 | - <div class="lazy-base-demo-wrap"> | |
4 | - <h1>向下滚动</h1> | |
5 | - | |
6 | - <div class="lazy-base-demo-box"> | |
7 | - <LazyContainer transitionName="custom"> | |
8 | - <TargetContent /> | |
9 | - </LazyContainer> | |
10 | - </div> | |
11 | - </div> | |
12 | - </PageWrapper> | |
13 | -</template> | |
14 | -<script lang="ts"> | |
15 | - import { defineComponent } from 'vue'; | |
16 | - import TargetContent from './TargetContent.vue'; | |
17 | - import { LazyContainer } from '/@/components/Container/index'; | |
18 | - import { PageWrapper } from '/@/components/Page'; | |
19 | - | |
20 | - export default defineComponent({ | |
21 | - components: { LazyContainer, TargetContent, PageWrapper }, | |
22 | - }); | |
23 | -</script> | |
24 | -<style lang="less"> | |
25 | - .lazy-base-demo { | |
26 | - &-wrap { | |
27 | - display: flex; | |
28 | - flex-direction: column; | |
29 | - align-items: center; | |
30 | - justify-content: center; | |
31 | - width: 50%; | |
32 | - height: 2000px; | |
33 | - margin: 20px auto; | |
34 | - background-color: @component-background; | |
35 | - text-align: center; | |
36 | - } | |
37 | - | |
38 | - &-box { | |
39 | - width: 300px; | |
40 | - height: 300px; | |
41 | - } | |
42 | - | |
43 | - h1 { | |
44 | - height: 1300px; | |
45 | - margin: 20px 0; | |
46 | - } | |
47 | - } | |
48 | - | |
49 | - .custom-enter { | |
50 | - transform: scale(0.4) translate(100%); | |
51 | - opacity: 0; | |
52 | - } | |
53 | - | |
54 | - .custom-enter-to { | |
55 | - opacity: 1; | |
56 | - } | |
57 | - | |
58 | - .custom-enter-active { | |
59 | - position: absolute; | |
60 | - top: 0; | |
61 | - width: 100%; | |
62 | - transition: all 0.5s; | |
63 | - } | |
64 | - | |
65 | - .custom-leave { | |
66 | - opacity: 1; | |
67 | - } | |
68 | - | |
69 | - .custom-leave-to { | |
70 | - transform: scale(0.4) translate(-100%); | |
71 | - opacity: 0; | |
72 | - } | |
73 | - | |
74 | - .custom-leave-active { | |
75 | - transition: all 0.5s; | |
76 | - } | |
77 | -</style> |
src/views/demo/comp/lazy/index.vue deleted
100644 → 0
1 | -<template> | |
2 | - <PageWrapper title="懒加载基础示例" content="向下滚动到可见区域才会加载组件"> | |
3 | - <div class="lazy-base-demo-wrap"> | |
4 | - <h1>向下滚动</h1> | |
5 | - | |
6 | - <div class="lazy-base-demo-box"> | |
7 | - <LazyContainer> | |
8 | - <TargetContent /> | |
9 | - <template #skeleton> | |
10 | - <Skeleton :rows="10" /> | |
11 | - </template> | |
12 | - </LazyContainer> | |
13 | - </div> | |
14 | - </div> | |
15 | - </PageWrapper> | |
16 | -</template> | |
17 | -<script lang="ts"> | |
18 | - import { defineComponent } from 'vue'; | |
19 | - import { Skeleton } from 'ant-design-vue'; | |
20 | - import TargetContent from './TargetContent.vue'; | |
21 | - import { LazyContainer } from '/@/components/Container/index'; | |
22 | - import { PageWrapper } from '/@/components/Page'; | |
23 | - | |
24 | - export default defineComponent({ | |
25 | - components: { LazyContainer, PageWrapper, TargetContent, Skeleton }, | |
26 | - }); | |
27 | -</script> | |
28 | -<style lang="less"> | |
29 | - .lazy-base-demo { | |
30 | - &-wrap { | |
31 | - display: flex; | |
32 | - flex-direction: column; | |
33 | - align-items: center; | |
34 | - justify-content: center; | |
35 | - width: 50%; | |
36 | - height: 2000px; | |
37 | - margin: 20px auto; | |
38 | - background-color: @component-background; | |
39 | - text-align: center; | |
40 | - } | |
41 | - | |
42 | - &-box { | |
43 | - width: 300px; | |
44 | - height: 300px; | |
45 | - } | |
46 | - | |
47 | - h1 { | |
48 | - height: 1300px; | |
49 | - margin: 20px 0; | |
50 | - } | |
51 | - } | |
52 | -</style> |