diff --git a/packages/frontend/src/components/global/MkLazy.vue b/packages/frontend/src/components/global/MkLazy.vue new file mode 100644 index 000000000..6d7ff4ca4 --- /dev/null +++ b/packages/frontend/src/components/global/MkLazy.vue @@ -0,0 +1,53 @@ +<!-- +SPDX-FileCopyrightText: syuilo and other misskey contributors +SPDX-License-Identifier: AGPL-3.0-only +--> + +<template> +<div ref="rootEl" :class="$style.root"> + <div v-if="!showing" :class="$style.placeholder"></div> + <slot v-else></slot> +</div> +</template> + +<script lang="ts" setup> +import { nextTick, onMounted, onActivated, onBeforeUnmount, ref, shallowRef } from 'vue'; + +const rootEl = shallowRef<HTMLDivElement>(); +const showing = ref(false); + +const observer = new IntersectionObserver( + (entries) => { + if (entries.some((entry) => entry.isIntersecting)) { + showing.value = true; + } + }, +); + +onMounted(() => { + nextTick(() => { + observer.observe(rootEl.value!); + }); +}); + +onActivated(() => { + nextTick(() => { + observer.observe(rootEl.value!); + }); +}); + +onBeforeUnmount(() => { + observer.disconnect(); +}); +</script> + +<style lang="scss" module> +.root { + display: block; +} + +.placeholder { + display: block; + min-height: 150px; +} +</style> diff --git a/packages/frontend/src/components/index.ts b/packages/frontend/src/components/index.ts index c740d181f..a3e13c3a5 100644 --- a/packages/frontend/src/components/index.ts +++ b/packages/frontend/src/components/index.ts @@ -25,6 +25,7 @@ import MkPageHeader from './global/MkPageHeader.vue'; import MkSpacer from './global/MkSpacer.vue'; import MkFooterSpacer from './global/MkFooterSpacer.vue'; import MkStickyContainer from './global/MkStickyContainer.vue'; +import MkLazy from './global/MkLazy.vue'; export default function(app: App) { for (const [key, value] of Object.entries(components)) { @@ -53,6 +54,7 @@ export const components = { MkSpacer: MkSpacer, MkFooterSpacer: MkFooterSpacer, MkStickyContainer: MkStickyContainer, + MkLazy: MkLazy, }; declare module '@vue/runtime-core' { @@ -77,5 +79,6 @@ declare module '@vue/runtime-core' { MkSpacer: typeof MkSpacer; MkFooterSpacer: typeof MkFooterSpacer; MkStickyContainer: typeof MkStickyContainer; + MkLazy: typeof MkLazy; } } diff --git a/packages/frontend/src/pages/user/home.vue b/packages/frontend/src/pages/user/home.vue index ecc3bb36c..a0163bfc6 100644 --- a/packages/frontend/src/pages/user/home.vue +++ b/packages/frontend/src/pages/user/home.vue @@ -128,12 +128,18 @@ SPDX-License-Identifier: AGPL-3.0-only </div> <MkInfo v-else-if="$i && $i.id === user.id">{{ i18n.ts.userPagePinTip }}</MkInfo> <template v-if="narrow"> - <XFiles :key="user.id" :user="user"/> - <XActivity :key="user.id" :user="user"/> + <MkLazy> + <XFiles :key="user.id" :user="user"/> + </MkLazy> + <MkLazy> + <XActivity :key="user.id" :user="user"/> + </MkLazy> </template> <div v-if="!disableNotes"> <div style="margin-bottom: 8px;">{{ i18n.ts.featured }}</div> - <MkNotes :class="$style.tl" :noGap="true" :pagination="pagination"/> + <MkLazy> + <MkNotes :class="$style.tl" :noGap="true" :pagination="pagination"/> + </MkLazy> </div> </div> </div>