Javascript6.1(リファクタリング+機能追加)

6から続きます。

2:リファクタリング+機能追加

mixinはいつもどおりなので省略

HTMLの記述

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.0.13/css/all.css" integrity="sha384-DNOHZ68U8hZfKXOrtjWvjxusGo9WQnrNx2sqG0tfsghAvtVlRW3tvkXWZh58N9jp" crossorigin="anonymous">
  <link href="https://fonts.googleapis.com/css2?family=Teko:wght@500&display=swap" rel="stylesheet">
  <link rel="stylesheet" href="style.css">
  <title>Document</title>
</head>
<body>
  <section>
    <div class="animate-title">Start Animation.</div>
  </section>
  <section>
    <div class="animate-title">Use what you have.</div>
  </section>
  <section>
    <div class="animate-title">Do what you can.</div>
  </section>
  <script src="text-animation.js"></script>
  <script src="scroll-polyfill.js"></script>
  <script src="scroll.js"></script>
  <script src="main.js"></script>
</body>
</html>

<script src=”scroll-polyfill.js”></script>を追加

SCSSの記述

@import "mixin";

html {
font-family: "Teko", sans-serif;
}
body {
margin: 0;
}
section {
position: relative;
height: 100vh;
background-color: teal;

&:nth-child(2) {
background-color: mediumvioletred;
}
&:nth-child(3) {
background-color: orange;
}
}
.animate-title,
.tween-animate-title {
position: absolute;
// 文字が画面中央に来るようにする
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
color: white;
opacity: 0;
font-size: 2em;

&.inview {
opacity: 1;

& .char {
display: inline-block;
}
}

& .char {
opacity: 0;
}
}

.animate-title.inview .char {
@include animation(
$name: kf-animate-chars,
$duration: 0.5s,
$timing-function: cubic-bezier(0.39, 1.57, 0.58, 1),
$fill-mode: both
);

@for $i from 1 through 30 {
&:nth-child(#{$i}) {
animation-delay: $i * 0.04s;
}
}
}

@keyframes kf-animate-chars {
0% {
opacity: 0;
transform: translateY(-50%);
}

100% {
opacity: 1;
transform: translateY(0);
}
}

main.jsの記述

document.addEventListener("DOMContentLoaded", function () {
// コールバック関数を設ける
  const cb = function (el, isIntersecting) {
  if (isIntersecting) {
  const ta = new TextAnimation(el);
  ta.animate();
  console.log(ta);
 }
};

// 第1引数にエレメント第二引数にコールバック関数
  const so = new ScrollObserver(".animate-title", cb);
  console.log(so);
});

scroll.jsの記述

// スクロールの監視を定義する
class ScrollObserver {
// 第一引数にanimate-title第2引数にコールバック関数第三引数にオプション
  constructor(els, cb, options) {
    this.els = document.querySelectorAll(els);
    console.log(this.els);
    const defaultOptions = {
    root: null,
    rootMargin: "0px",
    threshold: 0,
    once: true
     };
    this.cb = cb;
    console.log(this.cb);
// assignというメソッドででdefaultOptionsとoptionsをマージする
    this.options = Object.assign(defaultOptions, options);
    console.log(this.options);
    this.once = this.options.once;
    console.log(this.once);
    this._init();
    console.log(this._init);
}
// 初期化処理を記載して変数の記載漏れを防ぐ
_init() {
    const callback = function (entries, observer) {
      entries.forEach(entry => {
       if (entry.isIntersecting) {
        console.log(this);
        this.cb(entry.target, true);
       if (this.once) {
         observer.unobserve(entry.target);
      }
         } else {
           this.cb(entry.target, false);
       }
   });
};
// thisをbindで束縛するとScrollObserverのcb(コールバック関数)を参照する
    this.io = new IntersectionObserver(callback.bind(this), this.options);
    console.log(this.io)
// 後方互換性のためPolyfillの設定をする
    this.io.POLL_INTERVAL = 100;
// 要素が複数あるためループで回して監視
    this.els.forEach(el => this.io.observe(el));
}
// デストロイメソッドを追加して、監視をやめる
  destroy() {
    this.io.disconnect();
}
}

text-animation.jsの記述

// テキストアニメーションを定義
class TextAnimation {
  constructor(el) {
    this.DOM = {};
// elがDOMのときthis.Dom.elに格納、falseのときdocument.querySelector(el);でDOMを取得する
    this.DOM.el = el instanceof HTMLElement ? el : document.querySelector(el);
    console.log(this.DOM.el);
    this.chars = this.DOM.el.innerHTML.trim().split("");
    this.DOM.el.innerHTML = this._splitText();
    console.log(this.DOM.el.innerHTML);
  }
  _splitText() {
    return this.chars.reduce((acc, curr) => {
      curr = curr.replace(/\s+/, ' ');
      return `${acc}<span class="char">${curr}</span>`;
   }, "");
}
  animate() {
    this.DOM.el.classList.toggle('inview');
 }
}
class TweenTextAnimation extends TextAnimation {
  constructor(el) {
    super(el);
    this.DOM.chars = this.DOM.el.querySelectorAll('.char');
}

  animate() {
// inviewをつける
    this.DOM.el.classList.add('inview');
// TweenMaxの書き方(toメソッド)対象となるDOMアニメーションの間隔
    this.DOM.chars.forEach((c, i) => {
// オプションeaseファンクション,delayの間隔,オプション
      TweenMax.to(c, .6, {
        ease: Back.easeOut,
        delay: i * .05,
// アニメーションの始まる状態
        startAt: { y: '-50%', opacity: 0},
// 終了時の状態
        y: '0%',
        opacity: 1
    });
   });
 }
}
  1. document.querySelectorAll(els);でanimate-titleを取得したので出力された。

  2. console.log(this.cb);
    main.jsで定義したコールバック関数cbが入っているため。

  3. console.log(this.options);でoptionsにdefaultoptionsの初期設定をマージしたため

  4. console.log(this.once);onceをtrueに設定したため

  5. console.log(this.io)でクラスのIntersectionObserverが呼び出されて、callback関数

    を参照している

  6. console.log(this._init);の部分で_init()が呼び出されている

  7. console.log(so);の部分で、ScrollObserverが呼び出されていている。

  8. console.log(this);の部分で、ここのthisは直近のScrollObserverを参照している。

  9. console.log(this.DOM.el);の部分で、.animate-titleの部分を取得している

  10. console.log(this.DOM.el.innerHTML);の部分で、加工されたテキストが出力されている。

  11. console.log(ta);inviewが付加されて完成されたものが出力されている。

6.2に続きます

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です