mirror of
https://github.com/vbenjs/vue-vben-admin.git
synced 2025-01-24 10:33:50 +08:00
chore: remove LazyContainer
This commit is contained in:
parent
6890dd7201
commit
6a9bd686d5
@ -1,8 +1,8 @@
|
||||
import type { Ref } from 'vue';
|
||||
import { onBeforeUpdate, ref } from 'vue';
|
||||
import { onBeforeUpdate, shallowRef } from 'vue';
|
||||
|
||||
export function useRefs(): [Ref<HTMLElement[]>, (index: number) => (el: HTMLElement) => void] {
|
||||
const refs = ref([]) as Ref<HTMLElement[]>;
|
||||
const refs = shallowRef([]) as Ref<HTMLElement[]>;
|
||||
|
||||
onBeforeUpdate(() => {
|
||||
refs.value = [];
|
||||
|
@ -1,10 +1,8 @@
|
||||
import { withInstall } from '/@/utils';
|
||||
import collapseContainer from './src/collapse/CollapseContainer.vue';
|
||||
import scrollContainer from './src/ScrollContainer.vue';
|
||||
import lazyContainer from './src/LazyContainer.vue';
|
||||
|
||||
export const CollapseContainer = withInstall(collapseContainer);
|
||||
export const ScrollContainer = withInstall(scrollContainer);
|
||||
export const LazyContainer = withInstall(lazyContainer);
|
||||
|
||||
export * from './src/typing';
|
||||
|
@ -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>
|
@ -1,48 +0,0 @@
|
||||
import { Ref, watchEffect, ref } from 'vue';
|
||||
|
||||
interface IntersectionObserverProps {
|
||||
target: Ref<Element | null | undefined>;
|
||||
root?: Ref<any>;
|
||||
onIntersect: IntersectionObserverCallback;
|
||||
rootMargin?: string;
|
||||
threshold?: number;
|
||||
}
|
||||
|
||||
export function useIntersectionObserver({
|
||||
target,
|
||||
root,
|
||||
onIntersect,
|
||||
rootMargin = '0px',
|
||||
threshold = 0.1,
|
||||
}: IntersectionObserverProps) {
|
||||
let cleanup = () => {};
|
||||
const observer: Ref<Nullable<IntersectionObserver>> = ref(null);
|
||||
const stopEffect = watchEffect(() => {
|
||||
cleanup();
|
||||
|
||||
observer.value = new IntersectionObserver(onIntersect, {
|
||||
root: root ? root.value : null,
|
||||
rootMargin,
|
||||
threshold,
|
||||
});
|
||||
|
||||
const current = target.value;
|
||||
|
||||
current && observer.value.observe(current);
|
||||
|
||||
cleanup = () => {
|
||||
if (observer.value) {
|
||||
observer.value.disconnect();
|
||||
target.value && observer.value.unobserve(target.value);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
return {
|
||||
observer,
|
||||
stop: () => {
|
||||
cleanup();
|
||||
stopEffect();
|
||||
},
|
||||
};
|
||||
}
|
@ -1,8 +1,6 @@
|
||||
import type { ModalFunc, ModalFuncProps } from 'ant-design-vue/lib/modal/Modal';
|
||||
|
||||
import { Modal, message as Message, notification } from 'ant-design-vue';
|
||||
import { InfoCircleFilled, CheckCircleFilled, CloseCircleFilled } from '@ant-design/icons-vue';
|
||||
|
||||
import { NotificationArgsProps, ConfigProps } from 'ant-design-vue/lib/notification';
|
||||
import { useI18n } from './useI18n';
|
||||
import { isString } from '/@/utils/is';
|
||||
|
@ -29,10 +29,6 @@ export default {
|
||||
drawer: 'Drawer',
|
||||
desc: 'Desc',
|
||||
|
||||
lazy: 'Lazy',
|
||||
lazyBasic: 'Basic',
|
||||
lazyTransition: 'Animation',
|
||||
|
||||
verify: 'Verify',
|
||||
verifyDrag: 'Drag ',
|
||||
verifyRotate: 'Picture Restore',
|
||||
|
@ -28,10 +28,6 @@ export default {
|
||||
drawer: '抽屉扩展',
|
||||
desc: '详情组件',
|
||||
|
||||
lazy: '懒加载组件',
|
||||
lazyBasic: '基础示例',
|
||||
lazyTransition: '动画效果',
|
||||
|
||||
verify: '验证组件',
|
||||
verifyDrag: '拖拽校验',
|
||||
verifyRotate: '图片还原',
|
||||
|
@ -470,33 +470,6 @@ const comp: AppRouteModule = {
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
path: 'lazy',
|
||||
name: 'LazyDemo',
|
||||
component: getParentLayout('LazyDemo'),
|
||||
redirect: '/comp/lazy/basic',
|
||||
meta: {
|
||||
title: t('routes.demo.comp.lazy'),
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: 'basic',
|
||||
name: 'BasicLazyDemo',
|
||||
component: () => import('/@/views/demo/comp/lazy/index.vue'),
|
||||
meta: {
|
||||
title: t('routes.demo.comp.lazyBasic'),
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'transition',
|
||||
name: 'BasicTransitionDemo',
|
||||
component: () => import('/@/views/demo/comp/lazy/Transition.vue'),
|
||||
meta: {
|
||||
title: t('routes.demo.comp.lazyTransition'),
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: 'verify',
|
||||
name: 'VerifyDemo',
|
||||
|
@ -1,19 +0,0 @@
|
||||
<template>
|
||||
<Card hoverable :style="{ width: '240px', background: '#fff' }">
|
||||
<template #cover>
|
||||
<img alt="example" src="https://os.alipayobjects.com/rmsportal/QBnOOoLaAfKPirc.png" />
|
||||
</template>
|
||||
<CardMeta title="懒加载组件" />
|
||||
</Card>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import { Card } from 'ant-design-vue';
|
||||
|
||||
export default defineComponent({
|
||||
components: { CardMeta: Card.Meta, Card },
|
||||
setup() {
|
||||
return {};
|
||||
},
|
||||
});
|
||||
</script>
|
@ -1,77 +0,0 @@
|
||||
<template>
|
||||
<PageWrapper title="懒加载自定义动画示例" content="懒加载组件显示动画">
|
||||
<div class="lazy-base-demo-wrap">
|
||||
<h1>向下滚动</h1>
|
||||
|
||||
<div class="lazy-base-demo-box">
|
||||
<LazyContainer transitionName="custom">
|
||||
<TargetContent />
|
||||
</LazyContainer>
|
||||
</div>
|
||||
</div>
|
||||
</PageWrapper>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import TargetContent from './TargetContent.vue';
|
||||
import { LazyContainer } from '/@/components/Container/index';
|
||||
import { PageWrapper } from '/@/components/Page';
|
||||
|
||||
export default defineComponent({
|
||||
components: { LazyContainer, TargetContent, PageWrapper },
|
||||
});
|
||||
</script>
|
||||
<style lang="less">
|
||||
.lazy-base-demo {
|
||||
&-wrap {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 50%;
|
||||
height: 2000px;
|
||||
margin: 20px auto;
|
||||
background-color: @component-background;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
&-box {
|
||||
width: 300px;
|
||||
height: 300px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
height: 1300px;
|
||||
margin: 20px 0;
|
||||
}
|
||||
}
|
||||
|
||||
.custom-enter {
|
||||
transform: scale(0.4) translate(100%);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.custom-enter-to {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.custom-enter-active {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
transition: all 0.5s;
|
||||
}
|
||||
|
||||
.custom-leave {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.custom-leave-to {
|
||||
transform: scale(0.4) translate(-100%);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.custom-leave-active {
|
||||
transition: all 0.5s;
|
||||
}
|
||||
</style>
|
@ -1,52 +0,0 @@
|
||||
<template>
|
||||
<PageWrapper title="懒加载基础示例" content="向下滚动到可见区域才会加载组件">
|
||||
<div class="lazy-base-demo-wrap">
|
||||
<h1>向下滚动</h1>
|
||||
|
||||
<div class="lazy-base-demo-box">
|
||||
<LazyContainer>
|
||||
<TargetContent />
|
||||
<template #skeleton>
|
||||
<Skeleton :rows="10" />
|
||||
</template>
|
||||
</LazyContainer>
|
||||
</div>
|
||||
</div>
|
||||
</PageWrapper>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import { Skeleton } from 'ant-design-vue';
|
||||
import TargetContent from './TargetContent.vue';
|
||||
import { LazyContainer } from '/@/components/Container/index';
|
||||
import { PageWrapper } from '/@/components/Page';
|
||||
|
||||
export default defineComponent({
|
||||
components: { LazyContainer, PageWrapper, TargetContent, Skeleton },
|
||||
});
|
||||
</script>
|
||||
<style lang="less">
|
||||
.lazy-base-demo {
|
||||
&-wrap {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 50%;
|
||||
height: 2000px;
|
||||
margin: 20px auto;
|
||||
background-color: @component-background;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
&-box {
|
||||
width: 300px;
|
||||
height: 300px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
height: 1300px;
|
||||
margin: 20px 0;
|
||||
}
|
||||
}
|
||||
</style>
|
Loading…
Reference in New Issue
Block a user