|
@@ -1,145 +0,0 @@
|
|
|
-<template>
|
|
|
- <transition-group
|
|
|
- class="h-full w-full"
|
|
|
- v-bind="$attrs"
|
|
|
- ref="elRef"
|
|
|
- :name="transitionName"
|
|
|
- :tag="tag"
|
|
|
- mode="out-in"
|
|
|
- >
|
|
|
- <div key="component" v-if="isInit">
|
|
|
- <slot :loading="loading"></slot>
|
|
|
- </div>
|
|
|
- <div key="skeleton" v-else>
|
|
|
- <slot name="skeleton" v-if="$slots.skeleton"></slot>
|
|
|
- <Skeleton v-else />
|
|
|
- </div>
|
|
|
- </transition-group>
|
|
|
-</template>
|
|
|
-<script lang="ts">
|
|
|
- import type { PropType } from 'vue';
|
|
|
- import { defineComponent, reactive, onMounted, ref, toRef, toRefs } from 'vue';
|
|
|
- import { useTimeoutFn } from '@vben/hooks';
|
|
|
- import { Skeleton } from 'ant-design-vue';
|
|
|
- import { useIntersectionObserver } from '/@/hooks/event/useIntersectionObserver';
|
|
|
-
|
|
|
- interface State {
|
|
|
- isInit: boolean;
|
|
|
- loading: boolean;
|
|
|
- intersectionObserverInstance: IntersectionObserver | null;
|
|
|
- }
|
|
|
-
|
|
|
- const props = {
|
|
|
- /**
|
|
|
- * Waiting time, if the time is specified, whether visible or not, it will be automatically loaded after the specified time
|
|
|
- */
|
|
|
- timeout: { type: Number },
|
|
|
- /**
|
|
|
- * The viewport where the component is located.
|
|
|
- * If the component is scrolling in the page container, the viewport is the container
|
|
|
- */
|
|
|
- viewport: {
|
|
|
- type: (typeof window !== 'undefined' ? window.HTMLElement : Object) as PropType<HTMLElement>,
|
|
|
- default: () => null,
|
|
|
- },
|
|
|
- /**
|
|
|
- * Preload threshold, css unit
|
|
|
- */
|
|
|
- threshold: { type: String, default: '0px' },
|
|
|
- /**
|
|
|
- * The scroll direction of the viewport, vertical represents the vertical direction, horizontal represents the horizontal direction
|
|
|
- */
|
|
|
- direction: {
|
|
|
- type: String,
|
|
|
- default: 'vertical',
|
|
|
- validator: (v) => ['vertical', 'horizontal'].includes(v),
|
|
|
- },
|
|
|
- /**
|
|
|
- * The label name of the outer container that wraps the component
|
|
|
- */
|
|
|
- tag: { type: String, default: 'div' },
|
|
|
- maxWaitingTime: { type: Number, default: 80 },
|
|
|
- /**
|
|
|
- * transition name
|
|
|
- */
|
|
|
- transitionName: { type: String, default: 'lazy-container' },
|
|
|
- };
|
|
|
-
|
|
|
- export default defineComponent({
|
|
|
- name: 'LazyContainer',
|
|
|
- components: { Skeleton },
|
|
|
- inheritAttrs: false,
|
|
|
- props,
|
|
|
- emits: ['init'],
|
|
|
- setup(props, { emit }) {
|
|
|
- const elRef = ref();
|
|
|
- const state = reactive<State>({
|
|
|
- isInit: false,
|
|
|
- loading: false,
|
|
|
- intersectionObserverInstance: null,
|
|
|
- });
|
|
|
-
|
|
|
- onMounted(() => {
|
|
|
- immediateInit();
|
|
|
- initIntersectionObserver();
|
|
|
- });
|
|
|
-
|
|
|
- // If there is a set delay time, it will be executed immediately
|
|
|
- function immediateInit() {
|
|
|
- const { timeout } = props;
|
|
|
- timeout &&
|
|
|
- useTimeoutFn(() => {
|
|
|
- init();
|
|
|
- }, timeout);
|
|
|
- }
|
|
|
-
|
|
|
- function init() {
|
|
|
- state.loading = true;
|
|
|
-
|
|
|
- useTimeoutFn(() => {
|
|
|
- if (state.isInit) return;
|
|
|
- state.isInit = true;
|
|
|
- emit('init');
|
|
|
- }, props.maxWaitingTime || 80);
|
|
|
- }
|
|
|
-
|
|
|
- function initIntersectionObserver() {
|
|
|
- const { timeout, direction, threshold } = props;
|
|
|
- if (timeout) return;
|
|
|
- // According to the scrolling direction to construct the viewport margin, used to load in advance
|
|
|
- let rootMargin = '0px';
|
|
|
- switch (direction) {
|
|
|
- case 'vertical':
|
|
|
- rootMargin = `${threshold} 0px`;
|
|
|
- break;
|
|
|
- case 'horizontal':
|
|
|
- rootMargin = `0px ${threshold}`;
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- try {
|
|
|
- const { stop, observer } = useIntersectionObserver({
|
|
|
- rootMargin,
|
|
|
- target: toRef(elRef.value, '$el'),
|
|
|
- onIntersect: (entries: any[]) => {
|
|
|
- const isIntersecting = entries[0].isIntersecting || entries[0].intersectionRatio;
|
|
|
- if (isIntersecting) {
|
|
|
- init();
|
|
|
- if (observer) {
|
|
|
- stop();
|
|
|
- }
|
|
|
- }
|
|
|
- },
|
|
|
- root: toRef(props, 'viewport'),
|
|
|
- });
|
|
|
- } catch (e) {
|
|
|
- init();
|
|
|
- }
|
|
|
- }
|
|
|
- return {
|
|
|
- elRef,
|
|
|
- ...toRefs(state),
|
|
|
- };
|
|
|
- },
|
|
|
- });
|
|
|
-</script>
|