mirror of
https://github.com/vbenjs/vue-vben-admin.git
synced 2025-08-27 14:13:40 +08:00
perf(lazy-container): optimize lazyContainer code
This commit is contained in:
@@ -1,3 +0,0 @@
|
|||||||
> 1%
|
|
||||||
last 2 versions
|
|
||||||
not ie <= 10
|
|
@@ -2,7 +2,8 @@
|
|||||||
|
|
||||||
### ⚡ Performance Improvements
|
### ⚡ Performance Improvements
|
||||||
|
|
||||||
- 菜单性能继续优化
|
- 菜单性能继续优化,更流畅
|
||||||
|
- 优化懒加载组件及示例
|
||||||
|
|
||||||
### 🎫 Chores
|
### 🎫 Chores
|
||||||
|
|
||||||
@@ -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)
|
||||||
|
|
||||||
|
@@ -1,9 +1,16 @@
|
|||||||
<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 @@
|
|||||||
<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 @@
|
|||||||
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 @@
|
|||||||
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 @@
|
|||||||
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 @@
|
|||||||
});
|
});
|
||||||
</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 @@
|
|||||||
<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 @@
|
|||||||
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 @@
|
|||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: {
|
components: {
|
||||||
Skeleton,
|
Skeleton,
|
||||||
// LazyContainer,
|
LazyContainer,
|
||||||
CollapseHeader,
|
CollapseHeader,
|
||||||
CollapseTransition,
|
CollapseTransition,
|
||||||
},
|
},
|
||||||
@@ -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({
|
|||||||
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({
|
|||||||
|
|
||||||
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({
|
|||||||
</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({
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
return (
|
return (
|
||||||
imgState.show && (
|
imgState.show && (
|
||||||
|
@@ -18,6 +18,26 @@ const menu: MenuModule = {
|
|||||||
name: '动画组件',
|
name: '动画组件',
|
||||||
},
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
path: 'modal',
|
||||||
|
name: '弹窗扩展',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'drawer',
|
||||||
|
name: '抽屉扩展',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'desc',
|
||||||
|
name: '详情组件',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'qrcode',
|
||||||
|
name: '二维码组件',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'strength-meter',
|
||||||
|
name: '密码强度组件',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: 'scroll',
|
path: 'scroll',
|
||||||
name: '滚动组件',
|
name: '滚动组件',
|
||||||
@@ -36,21 +56,19 @@ 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 = {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
|
||||||
path: 'qrcode',
|
|
||||||
name: '二维码组件',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'strength-meter',
|
|
||||||
name: '密码强度组件',
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@@ -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',
|
||||||
|
80
src/views/demo/comp/lazy/Transition.vue
Normal file
80
src/views/demo/comp/lazy/Transition.vue
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
<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,7 +3,9 @@
|
|||||||
<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="() => {}">
|
|
||||||
|
<div class="lazy-base-demo-box">
|
||||||
|
<LazyContainer>
|
||||||
<TargetContent />
|
<TargetContent />
|
||||||
<template #skeleton>
|
<template #skeleton>
|
||||||
<Skeleton :rows="10" />
|
<Skeleton :rows="10" />
|
||||||
@@ -11,6 +13,7 @@
|
|||||||
</LazyContainer>
|
</LazyContainer>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
@@ -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 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&-box {
|
||||||
|
width: 300px;
|
||||||
|
height: 300px;
|
||||||
|
}
|
||||||
|
|
||||||
h1 {
|
h1 {
|
||||||
height: 1300px;
|
height: 1300px;
|
||||||
margin: 20px 0;
|
margin: 20px 0;
|
||||||
|
Reference in New Issue
Block a user