From fdeaa00bf24b0710ca341fafba8327c786ab9879 Mon Sep 17 00:00:00 2001 From: vben Date: Mon, 26 Oct 2020 00:34:23 +0800 Subject: [PATCH] feat: add lazyContainer comp and demo --- CHANGELOG.zh_CN.md | 1 + src/components/Container/index.ts | 2 +- .../Container/src/LazyContainer.less | 27 --- .../Container/src/LazyContainer.tsx | 200 ---------------- .../Container/src/LazyContainer.vue | 213 ++++++++++++++++++ src/router/menus/modules/demo/comp.ts | 4 + src/router/routes/modules/demo/comp.ts | 9 +- src/views/demo/comp/lazy/TargetContent.vue | 19 ++ src/views/demo/comp/lazy/index.vue | 46 ++++ 9 files changed, 292 insertions(+), 229 deletions(-) delete mode 100644 src/components/Container/src/LazyContainer.less delete mode 100644 src/components/Container/src/LazyContainer.tsx create mode 100644 src/components/Container/src/LazyContainer.vue create mode 100644 src/views/demo/comp/lazy/TargetContent.vue create mode 100644 src/views/demo/comp/lazy/index.vue diff --git a/CHANGELOG.zh_CN.md b/CHANGELOG.zh_CN.md index a3fa89e4..966a8afd 100644 --- a/CHANGELOG.zh_CN.md +++ b/CHANGELOG.zh_CN.md @@ -8,6 +8,7 @@ - 表单新增 submitOnReset 控制是否在重置时重新发起请求 - 表格新增`sortFn`支持自定义排序 - 新增动画组件及示例 +- 新增懒加载/延时加载组件及示例 ### ✨ Refactor diff --git a/src/components/Container/index.ts b/src/components/Container/index.ts index b6216d02..0365cb21 100644 --- a/src/components/Container/index.ts +++ b/src/components/Container/index.ts @@ -1,5 +1,5 @@ export { default as ScrollContainer } from './src/ScrollContainer.vue'; export { default as CollapseContainer } from './src/collapse/CollapseContainer.vue'; -export { default as LazyContainer } from './src/LazyContainer'; +export { default as LazyContainer } from './src/LazyContainer.vue'; export * from './src/types.d'; diff --git a/src/components/Container/src/LazyContainer.less b/src/components/Container/src/LazyContainer.less deleted file mode 100644 index 3e13b115..00000000 --- a/src/components/Container/src/LazyContainer.less +++ /dev/null @@ -1,27 +0,0 @@ -.lazy-container-enter { - opacity: 0; -} - -.lazy-container-enter-to { - opacity: 1; -} - -.lazy-container-enter-from, -.lazy-container-enter-active { - position: absolute; - top: 0; - width: 100%; - transition: opacity 0.3s 0.2s; -} - -.lazy-container-leave { - opacity: 1; -} - -.lazy-container-leave-to { - opacity: 0; -} - -.lazy-container-leave-active { - transition: opacity 0.5s; -} diff --git a/src/components/Container/src/LazyContainer.tsx b/src/components/Container/src/LazyContainer.tsx deleted file mode 100644 index 1c3bf4fc..00000000 --- a/src/components/Container/src/LazyContainer.tsx +++ /dev/null @@ -1,200 +0,0 @@ -import type { PropType } from 'vue'; - -import { - defineComponent, - reactive, - onMounted, - ref, - unref, - onUnmounted, - TransitionGroup, -} from 'vue'; - -import { Skeleton } from 'ant-design-vue'; -import { useRaf } from '/@/hooks/event/useRaf'; -import { useTimeout } from '/@/hooks/core/useTimeout'; -import { getListeners, getSlot } from '/@/utils/helper/tsxHelper'; - -import './LazyContainer.less'; - -interface State { - isInit: boolean; - loading: boolean; - intersectionObserverInstance: IntersectionObserver | null; -} -export default defineComponent({ - name: 'LazyContainer', - emits: ['before-init', 'init'], - props: { - // 等待时间,如果指定了时间,不论可见与否,在指定时间之后自动加载 - timeout: { - type: Number as PropType, - default: 8000, - // default: 8000, - }, - // 组件所在的视口,如果组件是在页面容器内滚动,视口就是该容器 - viewport: { - type: (typeof window !== 'undefined' ? window.HTMLElement : Object) as PropType, - default: () => null, - }, - // 预加载阈值, css单位 - threshold: { - type: String as PropType, - default: '0px', - }, - - // 视口的滚动方向, vertical代表垂直方向,horizontal代表水平方向 - direction: { - type: String as PropType<'vertical' | 'horizontal'>, - default: 'vertical', - }, - // 包裹组件的外层容器的标签名 - tag: { - type: String as PropType, - default: 'div', - }, - - maxWaitingTime: { - type: Number as PropType, - default: 80, - }, - - // 是否在不可见的时候销毁 - autoDestory: { - type: Boolean as PropType, - default: false, - }, - - // transition name - transitionName: { - type: String as PropType, - default: 'lazy-container', - }, - }, - setup(props, { attrs, emit, slots }) { - const elRef = ref(null); - const state = reactive({ - isInit: false, - loading: false, - intersectionObserverInstance: null, - }); - - // If there is a set delay time, it will be executed immediately - function immediateInit() { - const { timeout } = props; - timeout && - useTimeout(() => { - init(); - }, timeout); - } - - function init() { - // At this point, the skeleton component is about to be switched - emit('before-init'); - // At this point you can prepare to load the resources of the lazy-loaded component - state.loading = true; - - requestAnimationFrameFn(() => { - state.isInit = true; - emit('init'); - }); - } - function requestAnimationFrameFn(callback: () => any) { - // Prevent waiting too long without executing the callback - // Set the maximum waiting time - useTimeout(() => { - if (state.isInit) { - return; - } - callback(); - }, props.maxWaitingTime || 80); - - const { requestAnimationFrame } = useRaf(); - - return requestAnimationFrame; - } - function initIntersectionObserver() { - const { timeout, direction, threshold, viewport } = props; - if (timeout) { - return; - } - // According to the scrolling direction to construct the viewport margin, used to load in advance - let rootMargin; - switch (direction) { - case 'vertical': - rootMargin = `${threshold} 0px`; - break; - case 'horizontal': - rootMargin = `0px ${threshold}`; - break; - } - try { - // Observe the intersection of the viewport and the component container - state.intersectionObserverInstance = new window.IntersectionObserver(intersectionHandler, { - rootMargin, - root: viewport, - threshold: [0, Number.MIN_VALUE, 0.01], - }); - - const el = unref(elRef); - - state.intersectionObserverInstance.observe(el.$el); - } catch (e) { - init(); - } - } - // Cross-condition change handling function - function intersectionHandler(entries: any[]) { - const isIntersecting = entries[0].isIntersecting || entries[0].intersectionRatio; - if (isIntersecting) { - init(); - if (state.intersectionObserverInstance) { - const el = unref(elRef); - state.intersectionObserverInstance.unobserve(el.$el); - } - } - // else { - // const { autoDestory } = props; - // autoDestory && destory(); - // } - } - // function destory() { - // emit('beforeDestory'); - // state.loading = false; - // nextTick(() => { - // emit('destory'); - // }); - // } - - immediateInit(); - onMounted(() => { - initIntersectionObserver(); - }); - onUnmounted(() => { - // Cancel the observation before the component is destroyed - if (state.intersectionObserverInstance) { - const el = unref(elRef); - state.intersectionObserverInstance.unobserve(el.$el); - } - }); - - function renderContent() { - const { isInit, loading } = state; - if (isInit) { - return
{getSlot(slots, 'default', { loading })}
; - } - if (slots.skeleton) { - return
{getSlot(slots, 'skeleton') || }
; - } - return null; - } - return () => { - const { tag, transitionName } = props; - return ( - - {() => renderContent()} - - ); - }; - }, -}); diff --git a/src/components/Container/src/LazyContainer.vue b/src/components/Container/src/LazyContainer.vue new file mode 100644 index 00000000..676e5243 --- /dev/null +++ b/src/components/Container/src/LazyContainer.vue @@ -0,0 +1,213 @@ + + + diff --git a/src/router/menus/modules/demo/comp.ts b/src/router/menus/modules/demo/comp.ts index f86bded0..1ce4629c 100644 --- a/src/router/menus/modules/demo/comp.ts +++ b/src/router/menus/modules/demo/comp.ts @@ -48,6 +48,10 @@ const menu: MenuModule = { path: 'desc', name: '详情组件', }, + { + path: 'lazy', + name: '懒加载组件', + }, { path: 'verify', name: '验证组件', diff --git a/src/router/routes/modules/demo/comp.ts b/src/router/routes/modules/demo/comp.ts index cf1ad442..bde2ab33 100644 --- a/src/router/routes/modules/demo/comp.ts +++ b/src/router/routes/modules/demo/comp.ts @@ -99,7 +99,14 @@ export default { title: '详情组件', }, }, - + { + path: '/lazy', + name: 'lazyDemo', + component: () => import('/@/views/demo/comp/lazy/index.vue'), + meta: { + title: '懒加载组件', + }, + }, { path: '/verify', name: 'VerifyDemo', diff --git a/src/views/demo/comp/lazy/TargetContent.vue b/src/views/demo/comp/lazy/TargetContent.vue new file mode 100644 index 00000000..e0982542 --- /dev/null +++ b/src/views/demo/comp/lazy/TargetContent.vue @@ -0,0 +1,19 @@ + + diff --git a/src/views/demo/comp/lazy/index.vue b/src/views/demo/comp/lazy/index.vue new file mode 100644 index 00000000..d539073e --- /dev/null +++ b/src/views/demo/comp/lazy/index.vue @@ -0,0 +1,46 @@ + + + -- GitLab