101 lines
2.8 KiB
JavaScript
101 lines
2.8 KiB
JavaScript
/**
|
|
* TT-Core Intersection Observer Composable (Vue 3)
|
|
* Provides lazy-loading and visibility detection
|
|
*/
|
|
|
|
/**
|
|
* Create an intersection observer composable
|
|
* @param {Function} callback - Callback when element becomes visible
|
|
* @param {Object} options - Observer options
|
|
* @returns {Object} - Composable with ref and cleanup
|
|
*/
|
|
export function useIntersectionObserver(callback, options = {}) {
|
|
const { ref, onMounted, onBeforeUnmount } = Vue;
|
|
|
|
const targetRef = ref(null);
|
|
let observer = null;
|
|
|
|
onMounted(() => {
|
|
const threshold = options.threshold || 0.1;
|
|
const rootMargin = options.rootMargin || '0px';
|
|
const once = options.once !== undefined ? options.once : true;
|
|
|
|
observer = new IntersectionObserver(
|
|
([entry]) => {
|
|
if (entry.isIntersecting) {
|
|
callback(entry);
|
|
if (once && observer) {
|
|
observer.disconnect();
|
|
observer = null;
|
|
}
|
|
}
|
|
},
|
|
{ threshold, rootMargin, root: options.root || null }
|
|
);
|
|
|
|
if (targetRef.value) {
|
|
observer.observe(targetRef.value);
|
|
}
|
|
});
|
|
|
|
onBeforeUnmount(() => {
|
|
if (observer) {
|
|
observer.disconnect();
|
|
observer = null;
|
|
}
|
|
});
|
|
|
|
return {
|
|
targetRef
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Create an intersection observer mixin (backward compatibility)
|
|
* @param {Object} options - Observer options
|
|
* @returns {Object} - Vue mixin
|
|
*/
|
|
export function createIntersectionObserverMixin(options = {}) {
|
|
return {
|
|
data() {
|
|
return {
|
|
isVisible: false,
|
|
hasBeenVisible: false,
|
|
observer: null
|
|
};
|
|
},
|
|
mounted() {
|
|
this.setupObserver();
|
|
},
|
|
beforeUnmount() {
|
|
if (this.observer) {
|
|
this.observer.disconnect();
|
|
this.observer = null;
|
|
}
|
|
},
|
|
methods: {
|
|
setupObserver() {
|
|
const threshold = options.threshold || 0.1;
|
|
const rootMargin = options.rootMargin || '0px';
|
|
|
|
this.observer = new IntersectionObserver(
|
|
([entry]) => {
|
|
this.isVisible = entry.isIntersecting;
|
|
if (entry.isIntersecting && !this.hasBeenVisible) {
|
|
this.hasBeenVisible = true;
|
|
if (this.onFirstVisible) {
|
|
this.onFirstVisible();
|
|
}
|
|
}
|
|
},
|
|
{ threshold, rootMargin }
|
|
);
|
|
|
|
if (this.$refs.root) {
|
|
this.observer.observe(this.$refs.root);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}
|