🐉 Vue3 特定の要素までスクロールして画面に入ると発火する
作成日: 2023/09/22
0

特定の要素までスクロールして画面に入ると発火する

今回は前回の特定の要素の取得方法を使ってスクロールして発火するやつ。
javascriptだと(*引用元すずのん)

let targets = document.querySelectorAll('.js-scroll-fall'); //アニメーションさせたい要素
//スクロールイベント
window.addEventListener('scroll', function () {
  var scroll = window.scrollY; //スクロール量を取得
  var windowHeight = window.innerHeight; //画面の高さを取得
  for (let target of targets) { //ターゲット要素がある分、アニメーション用のクラスをつける処理を繰り返す
    var targetPos = target.getBoundingClientRect().top + scroll; //ターゲット要素の位置を取得
    if (scroll > targetPos - windowHeight) { //スクロール量 > ターゲット要素の位置
      target.classList.add('is-animated'); //is-animatedクラスを加える
    }
  }
});

jQueryだと(*引用元LOOP NEVER ENDS)

$(function(){
    //事前に要素のopacityを0(= 透明度100%)にしておく
    $('.item').css('opacity', 0);

    //要素が画面に入ったらopacityを1(= 透明度0%・不透明)にして表示する
    $('.item').on('inview', function(event, isInView) {
        if(isInView) { 
            $(this).animate({
                opacity : 1.0
            }, 1000);
        }
    });
});

上記にはWEB APIのgetBoundingClientRectが使われているが、分からなかったら調べてほしい。(Vue記事なので)

vue3では特定の要素を取得するrefonMountedそして新しくintersectionObserver APIを使う
inntersectionObserverは画面に要素が入っているかをtrue or falseで判断してくれる

Vue3での実装

<p ref="hello" class="ani" :class="{blue}">アニメーション</p>

要素にrefとバインドするクラス:classを指定する

const hello = ref();//タグにrefと同じ名前の変数をつける
const blue = ref(false);//最初はクラスを付けないのでfalse

// IntersectionObserver
const ISOServer = new IntersectionObserver(function(e){//1.eに返り値でターゲットが入る
  e.forEach(function(endpoint){// endpointには`IntersectionObserverEntry`が引き渡される
    console.log(endpoint.isIntersecting);//true or false
    if(endpoint.isIntersecting == false){
      //要素が入ってない時の処理
    }else{
      //要素が入った時の処理
      blue.value = true; //変数をバインドしたクラスをtrueに変更
    }
  })
},{//2.第二引数にoptionを引き取れる
  rootMargin: `0px 0px -300px 0px`//画面下から300pxのところで発火
})

onMounted(function(){
    const testDom = hellow.value;
    // IntersectionObserverに要素を渡す
  ISOServer.observe(testDom);//渡した物が1へと渡る
});

opstionを第二に入れる方法は上記の直接書く方法と

let option:{rootMargin:string} = {
  rootMargin: `0px 0px -300px 0px`
}
const options = ref(option);

// IntersectionObserver
const ISOServer = new IntersectionObserver(function(e){//1.eに返り値でターゲットが入る
  e.forEach(function(endpoint){// endpointには`IntersectionObserverEntry`が引き渡される
    console.log(endpoint.isIntersecting);//true or false
    if(endpoint.isIntersecting == false){
      //要素が入ってない時の処理
    }else{
      //要素が入った時の処理
      blue.value = true; //変数をバインドしたクラスをtrueに変更
    }
  })
},options.value)//ここに第2引数として渡す

上記の方法がある。メンテのしやすさで言うとobjに設定した後者が良さそうだけど・・・。

完成系

<template>
<p ref="hello" class="ani" :class="{blue}">アニメーション</p>
</template>

<script setup lang="ts">
import { ref, onMounted } from "vue";

const hello = ref();
const blue = ref(false);

const ISOServer = new IntersectionObserver(function(e){
  e.forEach(function(endpoint){
    if(endpoint.isIntersecting == false){
      //要素が入ってない時の処理
    }else{
      //要素が入った時の処理
      blue.value = true; 
    }
  })
},{
  rootMargin: `0px 0px -300px 0px`
})

onMounted(function(){
    const testDom = hellow.value;
  ISOServer.observe(testDom);
});
</script>

<style lang="scss" scoped>
.blue {
  animation: changeColor 5s ease-in forwards;
}
@keyframes changeColor {
  from {
    color: black;
  }
  to {
    color: blue;
  }
}
</style>

intersectionObserverについてもっと理解したい時はこちらで(*引用元[ふ]さん)


感想

他にも修正や編集できる所がある気がしている(やり方はいくつもありそう)
次はフェードイン・アウトをやる予定


フロントエンドエンジニアを頑張って勉強中。 最近はVueやNuxtを勉強中です。 コミュニティなどあれば参加してみたいと思ってます。 どうぞ、生暖かい目で見ていただけると幸いです。