提交 0f4b847d 作者: vben

perf(lazy-container): optimize lazyContainer code

上级 e79e540b
> 1%
last 2 versions
not ie <= 10
...@@ -2,7 +2,8 @@ ...@@ -2,7 +2,8 @@
### ⚡ Performance Improvements ### ⚡ Performance Improvements
- 菜单性能继续优化 - 菜单性能继续优化,更流畅
- 优化懒加载组件及示例
### 🎫 Chores ### 🎫 Chores
...@@ -13,6 +14,7 @@ ...@@ -13,6 +14,7 @@
### 🐛 Bug Fixes ### 🐛 Bug Fixes
- 修复升级之后 table 类型问题 - 修复升级之后 table 类型问题
- 修复分割菜单且左侧菜单没有数据时候,继续展示上一次子菜单的问题
## 2.0.0-rc.8 (2020-11-2) ## 2.0.0-rc.8 (2020-11-2)
......
<template> <template>
<transition-group v-bind="$attrs" ref="elRef" :name="transitionName" :tag="tag"> <transition-group
class="lazy-container"
v-bind="$attrs"
ref="elRef"
:name="transitionName"
:tag="tag"
mode="out-in"
>
<div key="component" v-if="isInit"> <div key="component" v-if="isInit">
<slot :loading="loading" /> <slot :loading="loading" />
</div> </div>
<div key="skeleton"> <div key="skeleton" v-else name="lazy-skeleton">
<slot name="skeleton" v-if="$slots.skeleton" /> <slot name="skeleton" v-if="$slots.skeleton" />
<Skeleton v-else /> <Skeleton v-else />
</div> </div>
...@@ -12,19 +19,9 @@ ...@@ -12,19 +19,9 @@
<script lang="ts"> <script lang="ts">
import type { PropType } from 'vue'; import type { PropType } from 'vue';
import { import { defineComponent, reactive, onMounted, ref, toRef, toRefs } from 'vue';
defineComponent,
reactive,
onMounted,
ref,
unref,
onUnmounted,
toRef,
toRefs,
} from 'vue';
import { Skeleton } from 'ant-design-vue'; import { Skeleton } from 'ant-design-vue';
import { useRaf } from '/@/hooks/event/useRaf';
import { useTimeout } from '/@/hooks/core/useTimeout'; import { useTimeout } from '/@/hooks/core/useTimeout';
import { useIntersectionObserver } from '/@/hooks/event/useIntersectionObserver'; import { useIntersectionObserver } from '/@/hooks/event/useIntersectionObserver';
interface State { interface State {
...@@ -36,13 +33,12 @@ ...@@ -36,13 +33,12 @@
name: 'LazyContainer', name: 'LazyContainer',
components: { Skeleton }, components: { Skeleton },
props: { props: {
// 等待时间,如果指定了时间,不论可见与否,在指定时间之后自动加载 // Waiting time, if the time is specified, whether visible or not, it will be automatically loaded after the specified time
timeout: { timeout: {
type: Number as PropType<number>, type: Number as PropType<number>,
default: 0,
// default: 8000,
}, },
// 组件所在的视口,如果组件是在页面容器内滚动,视口就是该容器
// The viewport where the component is located. If the component is scrolling in the page container, the viewport is the container
viewport: { viewport: {
type: (typeof window !== 'undefined' ? window.HTMLElement : Object) as PropType< type: (typeof window !== 'undefined' ? window.HTMLElement : Object) as PropType<
HTMLElement HTMLElement
...@@ -50,19 +46,19 @@ ...@@ -50,19 +46,19 @@
default: () => null, default: () => null,
}, },
// 预加载阈值, css单位 // Preload threshold, css unit
threshold: { threshold: {
type: String as PropType<string>, type: String as PropType<string>,
default: '0px', default: '0px',
}, },
// 视口的滚动方向, vertical代表垂直方向,horizontal代表水平方向 // The scroll direction of the viewport, vertical represents the vertical direction, horizontal represents the horizontal direction
direction: { direction: {
type: String as PropType<'vertical' | 'horizontal'>, type: String as PropType<'vertical' | 'horizontal'>,
default: 'vertical', default: 'vertical',
}, },
// 包裹组件的外层容器的标签名 // The label name of the outer container that wraps the component
tag: { tag: {
type: String as PropType<string>, type: String as PropType<string>,
default: 'div', default: 'div',
...@@ -105,23 +101,11 @@ ...@@ -105,23 +101,11 @@
function init() { function init() {
state.loading = true; 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(() => { useTimeout(() => {
if (state.isInit) return; if (state.isInit) return;
callback(); state.isInit = true;
emit('init');
}, props.maxWaitingTime || 80); }, props.maxWaitingTime || 80);
const { requestAnimationFrame } = useRaf();
return requestAnimationFrame;
} }
function initIntersectionObserver() { function initIntersectionObserver() {
...@@ -165,31 +149,8 @@ ...@@ -165,31 +149,8 @@
}); });
</script> </script>
<style lang="less"> <style lang="less">
.lazy-container-enter { .lazy-container {
opacity: 0;
}
.lazy-container-enter-to {
opacity: 1;
}
.lazy-container-enter-from,
.lazy-container-enter-active {
position: absolute;
top: 0;
width: 100%; width: 100%;
transition: opacity 0.3s 0.2s; height: 100%;
}
.lazy-container-leave {
opacity: 1;
}
.lazy-container-leave-to {
opacity: 0;
}
.lazy-container-leave-active {
transition: opacity 0.5s;
} }
</style> </style>
...@@ -8,13 +8,13 @@ ...@@ -8,13 +8,13 @@
<CollapseTransition :enable="canExpan"> <CollapseTransition :enable="canExpan">
<Skeleton v-if="loading" /> <Skeleton v-if="loading" />
<div class="collapse-container__body" v-else v-show="show"> <div class="collapse-container__body" v-else v-show="show">
<!-- <LazyContainer :timeout="lazyTime" v-if="lazy"> <LazyContainer :timeout="lazyTime" v-if="lazy">
<slot /> <slot />
<template #skeleton> <template #skeleton>
<slot name="lazySkeleton" /> <slot name="lazySkeleton" />
</template> </template>
</LazyContainer> --> </LazyContainer>
<slot /> <slot v-else />
</div> </div>
</CollapseTransition> </CollapseTransition>
</div> </div>
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
import CollapseHeader from './CollapseHeader.vue'; import CollapseHeader from './CollapseHeader.vue';
import { Skeleton } from 'ant-design-vue'; import { Skeleton } from 'ant-design-vue';
// import LazyContainer from '../LazyContainer'; import LazyContainer from '../LazyContainer.vue';
import { triggerWindowResize } from '/@/utils/event/triggerWindowResizeEvent'; import { triggerWindowResize } from '/@/utils/event/triggerWindowResizeEvent';
// hook // hook
...@@ -36,7 +36,7 @@ ...@@ -36,7 +36,7 @@
export default defineComponent({ export default defineComponent({
components: { components: {
Skeleton, Skeleton,
// LazyContainer, LazyContainer,
CollapseHeader, CollapseHeader,
CollapseTransition, CollapseTransition,
}, },
...@@ -75,7 +75,7 @@ ...@@ -75,7 +75,7 @@
// 延时加载时间 // 延时加载时间
lazyTime: { lazyTime: {
type: Number as PropType<number>, type: Number as PropType<number>,
default: 3000, default: 0,
}, },
}, },
setup(props) { setup(props) {
......
...@@ -25,11 +25,13 @@ export default defineComponent({ ...@@ -25,11 +25,13 @@ export default defineComponent({
const state = reactive({ const state = reactive({
show: false, show: false,
}); });
onMounted(() => { onMounted(() => {
nextTick(() => { nextTick(() => {
state.show = true; state.show = true;
}); });
}); });
onUnmounted(() => { onUnmounted(() => {
const el = unref(wrapRef); const el = unref(wrapRef);
el && document.body.removeChild(el); el && document.body.removeChild(el);
...@@ -61,6 +63,7 @@ export default defineComponent({ ...@@ -61,6 +63,7 @@ export default defineComponent({
handler && handler(); handler && handler();
} }
function renderContent(item: ContextMenuItem) { function renderContent(item: ContextMenuItem) {
const { icon, label } = item; const { icon, label } = item;
...@@ -72,6 +75,7 @@ export default defineComponent({ ...@@ -72,6 +75,7 @@ export default defineComponent({
</span> </span>
); );
} }
function renderMenuItem(items: ContextMenuItem[]) { function renderMenuItem(items: ContextMenuItem[]) {
return items.map((item, index) => { return items.map((item, index) => {
const { disabled, label, children, divider = false } = item; const { disabled, label, children, divider = false } = item;
......
...@@ -265,6 +265,7 @@ export default defineComponent({ ...@@ -265,6 +265,7 @@ export default defineComponent({
</div> </div>
); );
}; };
return () => { return () => {
return ( return (
imgState.show && ( imgState.show && (
......
...@@ -19,6 +19,26 @@ const menu: MenuModule = { ...@@ -19,6 +19,26 @@ const menu: MenuModule = {
}, },
{ {
path: 'modal',
name: '弹窗扩展',
},
{
path: 'drawer',
name: '抽屉扩展',
},
{
path: 'desc',
name: '详情组件',
},
{
path: 'qrcode',
name: '二维码组件',
},
{
path: 'strength-meter',
name: '密码强度组件',
},
{
path: 'scroll', path: 'scroll',
name: '滚动组件', name: '滚动组件',
children: [ children: [
...@@ -37,20 +57,18 @@ const menu: MenuModule = { ...@@ -37,20 +57,18 @@ const menu: MenuModule = {
], ],
}, },
{ {
path: 'modal',
name: '弹窗扩展',
},
{
path: 'drawer',
name: '抽屉扩展',
},
{
path: 'desc',
name: '详情组件',
},
{
path: 'lazy', path: 'lazy',
name: '懒加载组件', name: '懒加载组件',
children: [
{
path: 'basic',
name: '基础示例',
},
{
path: 'transition',
name: '动画效果',
},
],
}, },
{ {
path: 'verify', path: 'verify',
...@@ -66,14 +84,6 @@ const menu: MenuModule = { ...@@ -66,14 +84,6 @@ const menu: MenuModule = {
}, },
], ],
}, },
{
path: 'qrcode',
name: '二维码组件',
},
{
path: 'strength-meter',
name: '密码强度组件',
},
], ],
}, },
}; };
......
...@@ -99,13 +99,32 @@ export default { ...@@ -99,13 +99,32 @@ export default {
title: '详情组件', title: '详情组件',
}, },
}, },
{ {
path: '/lazy', path: '/lazy',
name: 'lazyDemo', name: 'lazyDemo',
component: () => import('/@/views/demo/comp/lazy/index.vue'), redirect: '/comp/lazy/basic',
meta: { meta: {
title: '懒加载组件', title: '懒加载组件',
}, },
children: [
{
path: 'basic',
name: 'BasicLazyDemo',
component: () => import('/@/views/demo/comp/lazy/index.vue'),
meta: {
title: '基础示例',
},
},
{
path: 'transition',
name: 'BasicTransitionDemo',
component: () => import('/@/views/demo/comp/lazy/Transition.vue'),
meta: {
title: '动画效果',
},
},
],
}, },
{ {
path: '/verify', path: '/verify',
......
<template>
<div class="p-4 lazy-base-demo">
<Alert message="自定义动画" description="懒加载组件显示动画" type="info" show-icon />
<div class="lazy-base-demo-wrap">
<h1>向下滚动</h1>
<div class="lazy-base-demo-box">
<LazyContainer transitionName="custom">
<TargetContent />
</LazyContainer>
</div>
</div>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import { Skeleton, Alert } from 'ant-design-vue';
import TargetContent from './TargetContent.vue';
import { LazyContainer } from '/@/components/Container/index';
export default defineComponent({
components: { LazyContainer, TargetContent, Skeleton, Alert },
setup() {
return {};
},
});
</script>
<style lang="less">
.lazy-base-demo {
&-wrap {
display: flex;
width: 50%;
height: 2000px;
margin: 20px auto;
text-align: center;
background: #fff;
justify-content: center;
flex-direction: column;
align-items: center;
}
&-box {
width: 300px;
height: 300px;
}
h1 {
height: 1300px;
margin: 20px 0;
}
}
.custom-enter {
opacity: 0;
transform: scale(0.4) translate(100%);
}
.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 {
opacity: 0;
transform: scale(0.4) translate(-100%);
}
.custom-leave-active {
transition: all 0.5s;
}
</style>
...@@ -3,12 +3,15 @@ ...@@ -3,12 +3,15 @@
<Alert message="基础示例" description="向下滚动到可见区域才会加载组件" type="info" show-icon /> <Alert message="基础示例" description="向下滚动到可见区域才会加载组件" type="info" show-icon />
<div class="lazy-base-demo-wrap"> <div class="lazy-base-demo-wrap">
<h1>向下滚动</h1> <h1>向下滚动</h1>
<LazyContainer @init="() => {}">
<TargetContent /> <div class="lazy-base-demo-box">
<template #skeleton> <LazyContainer>
<Skeleton :rows="10" /> <TargetContent />
</template> <template #skeleton>
</LazyContainer> <Skeleton :rows="10" />
</template>
</LazyContainer>
</div>
</div> </div>
</div> </div>
</template> </template>
...@@ -24,7 +27,7 @@ ...@@ -24,7 +27,7 @@
}, },
}); });
</script> </script>
<style lang="less" scoped> <style lang="less">
.lazy-base-demo { .lazy-base-demo {
&-wrap { &-wrap {
display: flex; display: flex;
...@@ -38,6 +41,11 @@ ...@@ -38,6 +41,11 @@
align-items: center; align-items: center;
} }
&-box {
width: 300px;
height: 300px;
}
h1 { h1 {
height: 1300px; height: 1300px;
margin: 20px 0; margin: 20px 0;
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论