Membuat Scroll Animation dengan Custome Directive di Vue 3

6 min read

# Introduction

Ketika kita sudah membuat sebuah website dan lagi mikir untuk kasih user experience yang lebih keren dengan memberikan sebuah animasi di website kita. Di artikel kali ini, saya akan memberikan tutorial cara membuat scroll animation menggunakan Intersection Observer. Untuk contoh studi kasus, kita akan membuat galeri, yang mana isi dari galeri tersebut kita fetch API dari Unsplash API.

# Apa itu Intersection Observer?

Intersection Observer adalah sebuah interface dari Intersection Observer API yang memberikan kita cara untuk mengamati suatu perubahan secara asynchronous pada element target terhadap viewport atau elemen ancestor.

Gampangnya, dengan Intersection Observer kita akan memantau suatu element apakah element tersebut sudah muncul di viewport browser atau belum. Berikut ini adalah contoh ilustrasinya

Ilustrasi elemen target yang sebagian berpotongan dengan viewport browser
Intersection Observer

Biasanya, Intersection Observer di gunakan untuk lazy loading, infinite scrolling, dan masih banyak lagi. Kali ini kita akan memanfaatkan Intersection Observer untuk membuat scroll animation pada project website kita.

1. Membuat Aplikasi di Unsplash Developers

Seperti yang sudah saya sampai di awal, kita akan membuat galeri foto dengan memanfaatkan API dari Unsplash. Pertama, silahkan masuk ke Unsplash Developers. Kemudian buat akun Unsplash Developers agar kita mendapatkan hak akses API. Jika sudah, kita akan diarahkan ke menu dashboard.

Dashboard Unsplash Developers

Buat aplikasi dan centang semua terms yang ada. Kemudian isi semua informasi aplikasi, jika sudah kita akan diarahkan ke halaman aplikasi yang sudah kita buat. Scroll kebawah sampai kita menemukan Keys yang akan kita gunakan, dan copy Access Key.

Access Key

2. Testing API menggunakan Postman

Untuk testing API, kita akan menggunakan aplikasi Postman. Jika kalian belum menginstall aplikasi Postman, silahkan download di sini.

Buka aplikasi Postman, dan paste link dibawah ini

https://api.unsplash.com/photos/?client_id=YOUR_ACCESS_KEY

Jika hasilnya sudah seperti ini, maka kita sudah dapat menggunakan API dari Unsplash. Testing API

3. Install Vue

Di project kali ini kita akan menggunakan Vue 3 dengan Vite. Silahkan jalankan perintah dibawah ini pada terminal untuk memulai project Vue.

#npm
npm create vite@latest nama-project -- --template vue

# yarn
yarn create vite nama-project --template vue

Perintah tersebut akan memunculkan opsi pilihan framework apa yang akan kita gunakan, pilih framework vue.

vanilla
> vue
react
preact
lit-element
svelte

Jika sudah, akan muncul opsi pilihan lagi. Yaitu apakah kita akan menggunakan pure js atau typescript. Pilih saja sesuai dengan selera kalian, kali ini saya akan menggunakan pure js.

❯ vue
 vue-ts

Setelah selesai nanti akan dibuatkan folder sesuai nama project yang kita ketik sebelumnya. Masuk ke dalam folder project lalu install dependecies.

cd nama-project

npm install
or
yarn install

Buka project di text editor kemudian jalankan perintah npm run dev atau yarn dev di terminal. Maka tampilannya akan seperti ini. first view

4. Desain Layout & Fetch API

Kita akan mendesain layout dengan masonry grid. Hapus semua component yang ada di folder component, kemudian salin code ini ke dalam file App.vue

<template>
  <div class="container">
    <h1>My Gallery</h1>
    <div class="container-photo">
      <figure v-for="image in galleries" :key="image.id">
        <img :src="image.urls.regular" :alt="image.alt_description" />
      </figure>
    </div>
  </div>
</template>

CSS

.container {
  max-width: 48rem;
  margin: 0 auto;
}

.container-photo {
  column-count: 2;
}

@media (min-width: 768px) {
  .container-photo {
    column-count: 3;
    column-gap: 10px;
  }
}

figure {
  margin: 0;
  display: grid;
  grid-template-rows: 1fr auto;
  margin-bottom: 10px;
  break-inside: avoid;
}

img {
  width: 100%;
  height: auto;
  border-radius: 1rem;
  object-fit: cover;
  box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
}

figure > img {
  grid-row: 1 / -1;
  grid-column: 1;
}

Jika kita lihat hasilnya memang belum ada, itu karena kita belum melakukan fetch ke Unsplash API yang sudah kita punya tadi. Sekarang kita buat fungsi fetch API di file App.vue dalam tag script

<script>
import { ref } from "vue"

export default {
  setup() {
    const galleries = ref([])

    const fetchImage = () => {
      fetch(`https://api.unsplash.com/photos/?client_id=${import.meta.env.VITE_ACCESS_KEY}&per_page=30`)
        .then(res => res.json())
        .then(response => galleries.value = response)
        .catch(error => console.log(error))
    }

    fetchImage()

    return { galleries }
  }
}
</script>

Buat file .env di root folder project kalian, kemudian isikan dengan access key yang sudah kalian punya.

VITE_ACCESS_KEY=ACCESS_KEY

Maka hasilnya akan menjadi seperti ini

Masonry Grid

Nice! Kita sudah membuat desain layout dengan masonry grid dan sudah terhubung ke API, selanjutnya kita buat animasi ketika di scroll.

5. Membuat Custome Directive

Buat folder directives di dalam folder src, dan beri nama scrollAnimation.js. Salin kode ini ke dalam file scrollAnimation.js

const options = { threshold: 0.5 }

const observer = new IntersectionObserver((entries, observer) => {
  let delay = 0
  entries.forEach((entry) => {
    if (entry.isIntersecting) {
      setTimeout(() => {
        entry.target.classList.add('enter')
        entry.target.classList.remove('before-enter')
      }, delay)
      delay += 150
      observer.unobserve(entry.target)
    }
  })
}, options)

export default {
  mounted(el) {
    el.classList.add('before-enter')
    observer.observe(el)
  },
}

Coba kita bedah kode di atas satu persatu

  1. Baris pertama kita membuat variabel options berisi objek threshold untuk menentukan pada saat berapa persen element muncul di viewport. Pada kode di atas kita memberikan threshold 0.5 yang artinya sebersar 50%. Variabel ini kita gunakan pada parameter IntersectionObserver.
  2. Kemudian kita membuat variabel observer yang berisikan IntersectionObserver. Pada IntersectionObserver terdapat dua parameter yaitu callback dan options. Nah pada parameter callback kita membuat fungsi dengan variabel entries dan observer, kemudian untuk paramter options kita masukkan variabel yang sudah kita buat pertama dengan nama variabel options juga.
  3. Didalam fungsi callback kita membuat variabel delay yang nantinya akan digunakan untuk memberi delay pada setiap element yang sudah masuk ke viewport.
  4. Kita memberikan kondisi, jika element sudah ter-intersecting dengan property isIntersecting dan menambah fungsi setTimeout untuk memberi delay setiap element yang sudah masuk viewport.
  5. Kemduian terdapat variabel observer dengan method unboserve yang berfungsi jika element sudah muncul di viewport, maka element tersebut tidak perlu di observe lagi jika keluar dari viewport.
  6. Kita export kemudian berikan method mounted yang ada di VueJS. Mounted berfungsi jika semua component sudah selesai dirender, maka jalankan semua fungsi yang ada didalam method mounted.

Untuk lebih jelasnya lagi tentang IntersectionObserver, bisa lihat di sini.

Masuk ke file main.js kemudian import directive yang sudah kita buat tadi.

import { createApp } from 'vue'
import App from './App.vue'
import ScrollAnimation from './directives/scrollAnimation'

createApp(App).directive('scrollanimation', ScrollAnimation).mount('#app')

Pada kode di atas, method directive terdapat dua parameter. Parameter pertama adalah custome directive yang akan kita gunakan file .vue dan parameter kedua merupakan fungsi dari directive tersebut. Untuk lebih jelasnya tentang custome directive, bisa lihat di sini

Kembali ke file App.vue, kemudian tambahkan directive yang baru kita buat ke tag html img

...
<img v-scrollanimation :src="image.urls.regular" :alt="image.alt_description" />
...

Tambahkan sedikit css

.before-enter {
  transform: translateY(50px);
  opacity: 0;
}

.enter {
  transform: translateX(0);
  opacity: 1;
  transition: 0.6s cubic-bezier(0.16, 1, 0.3, 1);
}

Berikut ini adalah hasilnya. Result

Wow! Sekarang kita sudah berhasil membuat scroll animation menggunakan IntersectionObserver dengan custome directive. Sekarang terlihat keren bukan?

# Closing

Jika punya pendekatan yang lebih baik, boleh sekali untuk memberikan saran agar penulisan kode menjadi lebih baik lagi. Semoga artikel ini bermanfaat. Goodluck!

Source Code

Referensi

Bagikan ke