vuetify
Version:
Vue Material Component Framework
88 lines (87 loc) • 2.84 kB
JavaScript
// Utilities
import { computed, getCurrentInstance, onBeforeUnmount, onMounted, ref, watch } from 'vue';
import { consoleWarn, propsFactory } from "../util/index.mjs"; // Types
// Composables
export const makeScrollProps = propsFactory({
scrollTarget: {
type: String
},
scrollThreshold: {
type: [String, Number]
}
}, 'scroll');
export function useScroll(props) {
let args = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
const {
thresholdMetCallback,
scrollThreshold,
canScroll
} = args;
let previousScroll = 0;
const target = ref(null);
const currentScroll = ref(0);
const savedScroll = ref(0);
const currentThreshold = ref(0);
const isScrollActive = ref(false);
const isScrollingUp = ref(false);
const computedScrollThreshold = computed(() => {
return Number(props.scrollThreshold ?? scrollThreshold ?? 300);
});
const onScroll = () => {
const targetEl = target.value;
if (!targetEl || canScroll && !canScroll.value) return;
previousScroll = currentScroll.value;
currentScroll.value = 'window' in targetEl ? targetEl.pageYOffset : targetEl.scrollTop;
isScrollingUp.value = currentScroll.value < previousScroll;
currentThreshold.value = Math.abs(currentScroll.value - computedScrollThreshold.value);
};
watch(isScrollingUp, () => {
savedScroll.value = savedScroll.value || currentScroll.value;
});
watch(isScrollActive, () => {
savedScroll.value = 0;
});
onMounted(() => {
watch(() => props.scrollTarget, scrollTarget => {
const newTarget = scrollTarget ? document.querySelector(scrollTarget) : window;
if (!newTarget) {
consoleWarn(`Unable to locate element with identifier ${scrollTarget}`, getCurrentInstance());
return;
}
if (newTarget === target.value) return;
target.value?.removeEventListener('scroll', onScroll);
target.value = newTarget;
target.value.addEventListener('scroll', onScroll, {
passive: true
});
}, {
immediate: true
});
});
onBeforeUnmount(() => {
target.value?.removeEventListener('scroll', onScroll);
});
thresholdMetCallback && watch(() => Math.abs(currentScroll.value - savedScroll.value) > computedScrollThreshold.value, thresholdMet => {
thresholdMet && thresholdMetCallback({
currentThreshold: currentThreshold.value,
isScrollingUp: isScrollingUp.value,
savedScroll
});
}, {
immediate: true
});
// Do we need this? If yes - seems that
// there's no need to expose onScroll
canScroll && watch(canScroll, onScroll, {
immediate: true
});
return {
isScrollActive,
// required only for testing
// probably can be removed
// later (2 chars chlng)
isScrollingUp,
savedScroll
};
}
//# sourceMappingURL=scroll.mjs.map