enhance(client): better sticky-container component
This commit is contained in:
		
							parent
							
								
									ef83670716
								
							
						
					
					
						commit
						f9ba35d928
					
				
					 3 changed files with 24 additions and 34 deletions
				
			
		|  | @ -174,9 +174,6 @@ onUnmounted(() => { | ||||||
| .fdidabkb { | .fdidabkb { | ||||||
| 	--height: 60px; | 	--height: 60px; | ||||||
| 	display: flex; | 	display: flex; | ||||||
| 	position: sticky; |  | ||||||
| 	top: var(--stickyTop, 0); |  | ||||||
| 	z-index: 1000; |  | ||||||
| 	width: 100%; | 	width: 100%; | ||||||
| 	-webkit-backdrop-filter: var(--blur, blur(15px)); | 	-webkit-backdrop-filter: var(--blur, blur(15px)); | ||||||
| 	backdrop-filter: var(--blur, blur(15px)); | 	backdrop-filter: var(--blur, blur(15px)); | ||||||
|  |  | ||||||
|  | @ -1,6 +1,8 @@ | ||||||
| <template> | <template> | ||||||
| <div ref="rootEl"> | <div ref="rootEl"> | ||||||
|  | 	<div ref="headerEl"> | ||||||
| 		<slot name="header"></slot> | 		<slot name="header"></slot> | ||||||
|  | 	</div> | ||||||
| 	<div ref="bodyEl" :data-sticky-container-header-height="headerHeight"> | 	<div ref="bodyEl" :data-sticky-container-header-height="headerHeight"> | ||||||
| 		<slot></slot> | 		<slot></slot> | ||||||
| 	</div> | 	</div> | ||||||
|  | @ -8,39 +10,25 @@ | ||||||
| </template> | </template> | ||||||
| 
 | 
 | ||||||
| <script lang="ts" setup> | <script lang="ts" setup> | ||||||
| import { onMounted, onUnmounted } from 'vue'; | import { onMounted, onUnmounted, provide, inject, Ref, ref, watch } from 'vue'; | ||||||
| 
 | 
 | ||||||
| const props = withDefaults(defineProps<{ | const CURRENT_STICKY_TOP = Symbol('CURRENT_STICKY_TOP'); | ||||||
| 	autoSticky?: boolean; |  | ||||||
| }>(), { |  | ||||||
| 	autoSticky: false, |  | ||||||
| }); |  | ||||||
| 
 | 
 | ||||||
| const rootEl = $ref<HTMLElement>(); | const rootEl = $ref<HTMLElement>(); | ||||||
|  | const headerEl = $ref<HTMLElement>(); | ||||||
| const bodyEl = $ref<HTMLElement>(); | const bodyEl = $ref<HTMLElement>(); | ||||||
| 
 | 
 | ||||||
| let headerHeight = $ref<string | undefined>(); | 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 calc = () => { | ||||||
| 	const currentStickyTop = getComputedStyle(rootEl).getPropertyValue('--stickyTop') || '0px'; | 	childStickyTop = parentStickyTop.value + headerEl.offsetHeight; | ||||||
| 
 | 	headerHeight = headerEl.offsetHeight.toString(); | ||||||
| 	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'; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| const observer = new MutationObserver(() => { | const observer = new ResizeObserver(() => { | ||||||
| 	window.setTimeout(() => { | 	window.setTimeout(() => { | ||||||
| 		calc(); | 		calc(); | ||||||
| 	}, 100); | 	}, 100); | ||||||
|  | @ -49,11 +37,19 @@ const observer = new MutationObserver(() => { | ||||||
| onMounted(() => { | onMounted(() => { | ||||||
| 	calc(); | 	calc(); | ||||||
| 
 | 
 | ||||||
| 	observer.observe(rootEl, { | 	watch(parentStickyTop, calc); | ||||||
| 		attributes: false, | 
 | ||||||
| 		childList: true, | 	watch($$(childStickyTop), () => { | ||||||
| 		subtree: false, | 		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(() => { | onUnmounted(() => { | ||||||
|  |  | ||||||
|  | @ -152,9 +152,6 @@ onUnmounted(() => { | ||||||
| .fdidabkc { | .fdidabkc { | ||||||
| 	--height: 60px; | 	--height: 60px; | ||||||
| 	display: flex; | 	display: flex; | ||||||
| 	position: sticky; |  | ||||||
| 	top: var(--stickyTop, 0); |  | ||||||
| 	z-index: 1000; |  | ||||||
| 	width: 100%; | 	width: 100%; | ||||||
| 	-webkit-backdrop-filter: var(--blur, blur(15px)); | 	-webkit-backdrop-filter: var(--blur, blur(15px)); | ||||||
| 	backdrop-filter: var(--blur, blur(15px)); | 	backdrop-filter: var(--blur, blur(15px)); | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue