73 lines
2.4 KiB
JavaScript
73 lines
2.4 KiB
JavaScript
// Utilities
|
|
import { computed, onBeforeUnmount, onMounted, shallowRef, watch } from 'vue';
|
|
import { convertToUnit } from "../../util/index.mjs"; // Types
|
|
export function useSticky(_ref) {
|
|
let {
|
|
rootEl,
|
|
isSticky,
|
|
layoutItemStyles
|
|
} = _ref;
|
|
const isStuck = shallowRef(false);
|
|
const stuckPosition = shallowRef(0);
|
|
const stickyStyles = computed(() => {
|
|
const side = typeof isStuck.value === 'boolean' ? 'top' : isStuck.value;
|
|
return [isSticky.value ? {
|
|
top: 'auto',
|
|
bottom: 'auto',
|
|
height: undefined
|
|
} : undefined, isStuck.value ? {
|
|
[side]: convertToUnit(stuckPosition.value)
|
|
} : {
|
|
top: layoutItemStyles.value.top
|
|
}];
|
|
});
|
|
onMounted(() => {
|
|
watch(isSticky, val => {
|
|
if (val) {
|
|
window.addEventListener('scroll', onScroll, {
|
|
passive: true
|
|
});
|
|
} else {
|
|
window.removeEventListener('scroll', onScroll);
|
|
}
|
|
}, {
|
|
immediate: true
|
|
});
|
|
});
|
|
onBeforeUnmount(() => {
|
|
window.removeEventListener('scroll', onScroll);
|
|
});
|
|
let lastScrollTop = 0;
|
|
function onScroll() {
|
|
const direction = lastScrollTop > window.scrollY ? 'up' : 'down';
|
|
const rect = rootEl.value.getBoundingClientRect();
|
|
const layoutTop = parseFloat(layoutItemStyles.value.top ?? 0);
|
|
const top = window.scrollY - Math.max(0, stuckPosition.value - layoutTop);
|
|
const bottom = rect.height + Math.max(stuckPosition.value, layoutTop) - window.scrollY - window.innerHeight;
|
|
const bodyScroll = parseFloat(getComputedStyle(rootEl.value).getPropertyValue('--v-body-scroll-y')) || 0;
|
|
if (rect.height < window.innerHeight - layoutTop) {
|
|
isStuck.value = 'top';
|
|
stuckPosition.value = layoutTop;
|
|
} else if (direction === 'up' && isStuck.value === 'bottom' || direction === 'down' && isStuck.value === 'top') {
|
|
stuckPosition.value = window.scrollY + rect.top - bodyScroll;
|
|
isStuck.value = true;
|
|
} else if (direction === 'down' && bottom <= 0) {
|
|
stuckPosition.value = 0;
|
|
isStuck.value = 'bottom';
|
|
} else if (direction === 'up' && top <= 0) {
|
|
if (!bodyScroll) {
|
|
stuckPosition.value = rect.top + top;
|
|
isStuck.value = 'top';
|
|
} else if (isStuck.value !== 'top') {
|
|
stuckPosition.value = -top + bodyScroll + layoutTop;
|
|
isStuck.value = 'top';
|
|
}
|
|
}
|
|
lastScrollTop = window.scrollY;
|
|
}
|
|
return {
|
|
isStuck,
|
|
stickyStyles
|
|
};
|
|
}
|
|
//# sourceMappingURL=sticky.mjs.map
|