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 type { Ref } from 'vue';
|
||||||
import { onBeforeUpdate, ref } from 'vue';
|
import { onBeforeUpdate, shallowRef } from 'vue';
|
||||||
|
|
||||||
export function useRefs(): [Ref<HTMLElement[]>, (index: number) => (el: HTMLElement) => void] {
|
export function useRefs(): [Ref<HTMLElement[]>, (index: number) => (el: HTMLElement) => void] {
|
||||||
const refs = ref([]) as Ref<HTMLElement[]>;
|
const refs = shallowRef([]) as Ref<HTMLElement[]>;
|
||||||
|
|
||||||
onBeforeUpdate(() => {
|
onBeforeUpdate(() => {
|
||||||
refs.value = [];
|
refs.value = [];
|
||||||
|
@ -1,10 +1,8 @@
|
|||||||
import { withInstall } from '/@/utils';
|
import { withInstall } from '/@/utils';
|
||||||
import collapseContainer from './src/collapse/CollapseContainer.vue';
|
import collapseContainer from './src/collapse/CollapseContainer.vue';
|
||||||
import scrollContainer from './src/ScrollContainer.vue';
|
import scrollContainer from './src/ScrollContainer.vue';
|
||||||
import lazyContainer from './src/LazyContainer.vue';
|
|
||||||
|
|
||||||
export const CollapseContainer = withInstall(collapseContainer);
|
export const CollapseContainer = withInstall(collapseContainer);
|
||||||
export const ScrollContainer = withInstall(scrollContainer);
|
export const ScrollContainer = withInstall(scrollContainer);
|
||||||
export const LazyContainer = withInstall(lazyContainer);
|
|
||||||
|
|
||||||
export * from './src/typing';
|
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 type { ModalFunc, ModalFuncProps } from 'ant-design-vue/lib/modal/Modal';
|
||||||
|
|
||||||
import { Modal, message as Message, notification } from 'ant-design-vue';
|
import { Modal, message as Message, notification } from 'ant-design-vue';
|
||||||
import { InfoCircleFilled, CheckCircleFilled, CloseCircleFilled } from '@ant-design/icons-vue';
|
import { InfoCircleFilled, CheckCircleFilled, CloseCircleFilled } from '@ant-design/icons-vue';
|
||||||
|
|
||||||
import { NotificationArgsProps, ConfigProps } from 'ant-design-vue/lib/notification';
|
import { NotificationArgsProps, ConfigProps } from 'ant-design-vue/lib/notification';
|
||||||
import { useI18n } from './useI18n';
|
import { useI18n } from './useI18n';
|
||||||
import { isString } from '/@/utils/is';
|
import { isString } from '/@/utils/is';
|
||||||
|
@ -29,10 +29,6 @@ export default {
|
|||||||
drawer: 'Drawer',
|
drawer: 'Drawer',
|
||||||
desc: 'Desc',
|
desc: 'Desc',
|
||||||
|
|
||||||
lazy: 'Lazy',
|
|
||||||
lazyBasic: 'Basic',
|
|
||||||
lazyTransition: 'Animation',
|
|
||||||
|
|
||||||
verify: 'Verify',
|
verify: 'Verify',
|
||||||
verifyDrag: 'Drag ',
|
verifyDrag: 'Drag ',
|
||||||
verifyRotate: 'Picture Restore',
|
verifyRotate: 'Picture Restore',
|
||||||
|
@ -28,10 +28,6 @@ export default {
|
|||||||
drawer: '抽屉扩展',
|
drawer: '抽屉扩展',
|
||||||
desc: '详情组件',
|
desc: '详情组件',
|
||||||
|
|
||||||
lazy: '懒加载组件',
|
|
||||||
lazyBasic: '基础示例',
|
|
||||||
lazyTransition: '动画效果',
|
|
||||||
|
|
||||||
verify: '验证组件',
|
verify: '验证组件',
|
||||||
verifyDrag: '拖拽校验',
|
verifyDrag: '拖拽校验',
|
||||||
verifyRotate: '图片还原',
|
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',
|
path: 'verify',
|
||||||
name: 'VerifyDemo',
|
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