123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596 |
- import { createVNode as _createVNode, resolveDirective as _resolveDirective } from "vue";
- // Styles
- import "./VParallax.css";
- // Components
- import { VImg } from "../VImg/index.mjs"; // Composables
- import { useDisplay } from "../../composables/index.mjs";
- import { makeComponentProps } from "../../composables/component.mjs";
- import { useIntersectionObserver } from "../../composables/intersectionObserver.mjs";
- import { useResizeObserver } from "../../composables/resizeObserver.mjs"; // Utilities
- import { computed, onBeforeUnmount, ref, watch, watchEffect } from 'vue';
- import { clamp, genericComponent, getScrollParent, propsFactory, useRender } from "../../util/index.mjs"; // Types
- function floor(val) {
- return Math.floor(Math.abs(val)) * Math.sign(val);
- }
- export const makeVParallaxProps = propsFactory({
- scale: {
- type: [Number, String],
- default: 0.5
- },
- ...makeComponentProps()
- }, 'VParallax');
- export const VParallax = genericComponent()({
- name: 'VParallax',
- props: makeVParallaxProps(),
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const {
- intersectionRef,
- isIntersecting
- } = useIntersectionObserver();
- const {
- resizeRef,
- contentRect
- } = useResizeObserver();
- const {
- height: displayHeight
- } = useDisplay();
- const root = ref();
- watchEffect(() => {
- intersectionRef.value = resizeRef.value = root.value?.$el;
- });
- let scrollParent;
- watch(isIntersecting, val => {
- if (val) {
- scrollParent = getScrollParent(intersectionRef.value);
- scrollParent = scrollParent === document.scrollingElement ? document : scrollParent;
- scrollParent.addEventListener('scroll', onScroll, {
- passive: true
- });
- onScroll();
- } else {
- scrollParent.removeEventListener('scroll', onScroll);
- }
- });
- onBeforeUnmount(() => {
- scrollParent?.removeEventListener('scroll', onScroll);
- });
- watch(displayHeight, onScroll);
- watch(() => contentRect.value?.height, onScroll);
- const scale = computed(() => {
- return 1 - clamp(+props.scale);
- });
- let frame = -1;
- function onScroll() {
- if (!isIntersecting.value) return;
- cancelAnimationFrame(frame);
- frame = requestAnimationFrame(() => {
- const el = (root.value?.$el).querySelector('.v-img__img');
- if (!el) return;
- const scrollHeight = scrollParent instanceof Document ? document.documentElement.clientHeight : scrollParent.clientHeight;
- const scrollPos = scrollParent instanceof Document ? window.scrollY : scrollParent.scrollTop;
- const top = intersectionRef.value.getBoundingClientRect().top + scrollPos;
- const height = contentRect.value.height;
- const center = top + (height - scrollHeight) / 2;
- const translate = floor((scrollPos - center) * scale.value);
- const sizeScale = Math.max(1, (scale.value * (scrollHeight - height) + height) / height);
- el.style.setProperty('transform', `translateY(${translate}px) scale(${sizeScale})`);
- });
- }
- useRender(() => _createVNode(VImg, {
- "class": ['v-parallax', {
- 'v-parallax--active': isIntersecting.value
- }, props.class],
- "style": props.style,
- "ref": root,
- "cover": true,
- "onLoadstart": onScroll,
- "onLoad": onScroll
- }, slots));
- return {};
- }
- });
- //# sourceMappingURL=VParallax.mjs.map
|