A Vue3 component to detect when lazy component or HTML element is becoming visible/hidden on the page. The intersection can be observed once or listened by callback.
- π 0 dependencies: No worry about your bundle size
- β Type Strong: Written in Typescript
- π¦ Size: ~27kb
$ npm i vue3-deferred-content
# or
$ yarn add vue3-deferred-content
main.js:
import { createApp } from 'vue'
import App from './App.vue'
import VueDeferredContent from 'vue3-deferred-content'
const app = createApp(App)
const options = {
name: 'lazyContent', // by default: deferred
// by default for all components
rootMargin: '0px', // string
threshold: 0, // number | number[]
}
app.use(VueDeferredContent, options)
app.mount('#app')
- Standard example with callbacks.
<b>status: {{status}}</b>
<lazy-content
:auto-hide="false"
@enter="enterElement"
@leave="leaveElement"
@change="changeIntersect"
@disconnect="disconnect"
>
<img src="http://placekitten.com/360/280" alt="kitten">
<p>Number of changes: {{changeCount}}</p>
</lazy-content>
export default defineComponent({
name: 'Example1',
data:() => ({
changeCount: 0,
status: 'π Leave',
}),
methods: {
enterElement(target) {
this.status = 'π΅ Enter'
console.log(this.status, target)
},
leaveElement(target) {
this.status = 'π Leave'
console.log(this.status, target)
},
changeIntersect(target) {
this.changeCount++
console.log('Change', target)
},
disconnect() {
console.log('Disconnect')
},
},
})
- Called once after first enter.
<lazy-content
:once="true"
@change="changeIntersect"
>
<img src="http://placekitten.com/g/361/281" alt="kitten 2">
<p>Number of changes: {{changeCount}}</p>
</lazy-content>
export default defineComponent({
name: 'Example2',
data:() => ({
changeCount: 0,
}),
methods: {
changeIntersect(target) {
this.changeCount++
console.log('Change', target)
},
},
})
- Calling the module without callbacks. Lazy load image.
<lazy-content>
<img src="https://placekitten.com/362/282" alt="kitten 3">
</lazy-content>
- Lazy load image and Transition.
<lazy-content>
<transition name="fade" :appear="true">
<!-- This DIV tag is required for this example and I don't know why. :( -->
<div>
<img src="https://placekitten.com/400/300" alt="kitten 4">
</div>
</transition>
</lazy-content>
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.8s ease;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}
- Lazy load image and Transition group.
<lazy-content>
<transition-group name="list" :appear="true">
<span v-for="(item, index) in items" :key="item" class="list-item" :style="`transition-delay: ${index * 250}ms;`">
<img :src="item" alt="kitten 5">
</span>
</transition-group>
</lazy-content>
export default defineComponent({
name: 'Example5',
data:() => ({
items: [
'https://placekitten.com/360/280',
'https://placekitten.com/361/281',
'https://placekitten.com/362/282',
]
})
})
.placeholder {
display: flex;
flex-direction: row;
justify-content: space-around;
}
.list-item {
width: 30%;
}
.list-enter-active,
.list-leave-active {
transition: all 1s ease;
}
.list-enter-from,
.list-leave-to {
opacity: 0;
transform: translateY(30px);
}
- Async Component and Transition.
<lazy-content
:once="true"
>
<transition name="fade" :appear="true">
<AsyncComponent/>
</transition>
</lazy-content>
export default defineComponent({
name: 'Example6',
components: {
AsyncComponent: defineAsyncComponent(() => import('./AsyncComponent.vue')),
},
})
.fade-enter-active,
.fade-leave-active {
transition: opacity 15s ease;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}
- Test
Copyright (c) @yesworld