Skip to content

A Vue3 component to detect when a lazy component is becoming visible/hidden on the page.

License

Notifications You must be signed in to change notification settings

yesworld/vue3-deferred-content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

18 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Vue 3 Lazy load image and component / vue3-deferred-content

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.

πŸš€ Features

  • πŸ”— 0 dependencies: No worry about your bundle size
  • ✊ Type Strong: Written in Typescript
  • πŸ“¦ Size: ~27kb

Live demo πŸŽ‰

πŸ“¦ Installation

$ npm i vue3-deferred-content
# or
$ yarn add vue3-deferred-content

πŸ“Ž How to use?

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')

Examples

  1. 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')
    },
  },
})
  1. 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)
    },
  },
})
  1. Calling the module without callbacks. Lazy load image.
<lazy-content>
  <img src="https://placekitten.com/362/282" alt="kitten 3">
</lazy-content>
  1. 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;
}
  1. 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);
}
  1. 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;
}

TODO

  • Test

License

MIT License

Copyright (c) :suspect: @yesworld