From f9ba35d92882103702b9c33c5f0d1bbf98fc029f Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Sat, 2 Jul 2022 21:28:55 +0900 Subject: [PATCH] enhance(client): better sticky-container component --- .../src/components/global/page-header.vue | 3 -- .../components/global/sticky-container.vue | 52 +++++++++---------- packages/client/src/pages/admin/_header_.vue | 3 -- 3 files changed, 24 insertions(+), 34 deletions(-) diff --git a/packages/client/src/components/global/page-header.vue b/packages/client/src/components/global/page-header.vue index 5395a87961..0ab15e0ca3 100644 --- a/packages/client/src/components/global/page-header.vue +++ b/packages/client/src/components/global/page-header.vue @@ -174,9 +174,6 @@ onUnmounted(() => { .fdidabkb { --height: 60px; display: flex; - position: sticky; - top: var(--stickyTop, 0); - z-index: 1000; width: 100%; -webkit-backdrop-filter: var(--blur, blur(15px)); backdrop-filter: var(--blur, blur(15px)); diff --git a/packages/client/src/components/global/sticky-container.vue b/packages/client/src/components/global/sticky-container.vue index 98a7ee9c30..2603fac55d 100644 --- a/packages/client/src/components/global/sticky-container.vue +++ b/packages/client/src/components/global/sticky-container.vue @@ -1,6 +1,8 @@ <template> <div ref="rootEl"> - <slot name="header"></slot> + <div ref="headerEl"> + <slot name="header"></slot> + </div> <div ref="bodyEl" :data-sticky-container-header-height="headerHeight"> <slot></slot> </div> @@ -8,39 +10,25 @@ </template> <script lang="ts" setup> -import { onMounted, onUnmounted } from 'vue'; +import { onMounted, onUnmounted, provide, inject, Ref, ref, watch } from 'vue'; -const props = withDefaults(defineProps<{ - autoSticky?: boolean; -}>(), { - autoSticky: false, -}); +const CURRENT_STICKY_TOP = Symbol('CURRENT_STICKY_TOP'); const rootEl = $ref<HTMLElement>(); +const headerEl = $ref<HTMLElement>(); const bodyEl = $ref<HTMLElement>(); let headerHeight = $ref<string | undefined>(); +let childStickyTop = $ref(0); +const parentStickyTop = inject<Ref<number>>(CURRENT_STICKY_TOP, ref(0)); +provide(CURRENT_STICKY_TOP, $$(childStickyTop)); const calc = () => { - const currentStickyTop = getComputedStyle(rootEl).getPropertyValue('--stickyTop') || '0px'; - - const header = rootEl.children[0] as HTMLElement; - if (header === bodyEl) { - bodyEl.style.setProperty('--stickyTop', currentStickyTop); - } else { - bodyEl.style.setProperty('--stickyTop', `calc(${currentStickyTop} + ${header.offsetHeight}px)`); - headerHeight = header.offsetHeight.toString(); - - if (props.autoSticky) { - header.style.setProperty('--stickyTop', currentStickyTop); - header.style.position = 'sticky'; - header.style.top = 'var(--stickyTop)'; - header.style.zIndex = '1'; - } - } + childStickyTop = parentStickyTop.value + headerEl.offsetHeight; + headerHeight = headerEl.offsetHeight.toString(); }; -const observer = new MutationObserver(() => { +const observer = new ResizeObserver(() => { window.setTimeout(() => { calc(); }, 100); @@ -49,11 +37,19 @@ const observer = new MutationObserver(() => { onMounted(() => { calc(); - observer.observe(rootEl, { - attributes: false, - childList: true, - subtree: false, + watch(parentStickyTop, calc); + + watch($$(childStickyTop), () => { + bodyEl.style.setProperty('--stickyTop', `${childStickyTop}px`); + }, { + immediate: true, }); + + headerEl.style.position = 'sticky'; + headerEl.style.top = 'var(--stickyTop, 0)'; + headerEl.style.zIndex = '1000'; + + observer.observe(headerEl); }); onUnmounted(() => { diff --git a/packages/client/src/pages/admin/_header_.vue b/packages/client/src/pages/admin/_header_.vue index 1c3cdcb51f..73747e1164 100644 --- a/packages/client/src/pages/admin/_header_.vue +++ b/packages/client/src/pages/admin/_header_.vue @@ -152,9 +152,6 @@ onUnmounted(() => { .fdidabkc { --height: 60px; display: flex; - position: sticky; - top: var(--stickyTop, 0); - z-index: 1000; width: 100%; -webkit-backdrop-filter: var(--blur, blur(15px)); backdrop-filter: var(--blur, blur(15px));