Skip to content

Instantly share code, notes, and snippets.

@rdunk

rdunk/App.vue Secret

Created September 8, 2020 22:07
Show Gist options
  • Save rdunk/98c9c2a80dace8e73472b81e3e9ce97b to your computer and use it in GitHub Desktop.
Save rdunk/98c9c2a80dace8e73472b81e3e9ce97b to your computer and use it in GitHub Desktop.
Lazyload/Sleepy component
// Use the plugin
Vue.use(SleepyPlugin, {
rootMargin: '50%',
});
<template>
<sleepy-component @wake="doSomething">
<div>Lazyload this...</div>
</sleepy-component>
</template>
const inBrowser = typeof window !== 'undefined';
class Sleepy {
constructor(options) {
this.sleepers = [];
this.observer = this.createObserver(options);
}
createObserver(options) {
if (inBrowser) {
return new IntersectionObserver(this.onIntersect.bind(this), options);
}
return null;
}
onIntersect(entries) {
entries.forEach((entry) => {
if (entry.isIntersecting) {
const sleeper = this.sleepers.find(s => s.$el === entry.target);
if (sleeper) {
sleeper.wake();
}
}
});
}
addSleeper(component) {
this.sleepers.push(component);
if (this.observer) {
this.observer.observe(component.$el);
}
}
removeSleeper(component) {
const index = this.sleepers.find(l => l.$el === component.el);
if (index > -1) {
this.sleepers.splice(index, 1);
}
if (this.observer) {
this.observer.unobserve(component.$el);
}
}
}
const SleepyComponent = sleepy => ({
data() {
return {
awake: false,
};
},
render(h) {
if (this.awake) return h('div', null, this.$slots.default);
return h('div', { style: 'height: 1px; margin-top: -1px;' });
},
methods: {
wake() {
this.awake = true;
this.unobserve();
this.$emit('wake');
},
observe() {
sleepy.addSleeper(this);
},
unobserve() {
sleepy.removeSleeper(this);
},
},
mounted() {
this.observe();
},
destroyed() {
this.unobserve();
},
});
export default {
install(Vue, options = {}) {
const sleepy = new Sleepy(options);
Vue.component('sleepy-component', SleepyComponent(sleepy));
},
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment