5.5から続く
1:画面のスクロールを検知してテキストアニメーションをする
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>
<!-- main.jsよりも先に読み込ませる -->
<script src="text-animation.js"></script>
<script src="main.js"></script>
</body>
</html>
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 () {
// .animate-titleの要素を取得(複数取得したいのでAll)
const els = document.querySelectorAll('.animate-title');
const cb = function (entries, observer) {
entries.forEach(entry => {
if (entry.isIntersecting) {
// entry.targetにしないとエラー
const ta = new TextAnimation(entry.target);
ta.animate();
//一度アニメーションが実行されたら監視をやめる
observer.unobserve(entry.target);
} else {
}
});
};
// よく使うオプション
const options = {
// 交差対象の親要素
root: null,
//左右で設定すると交差しない場合があるので注意!
rootMargin: "0px",
//設定すると判定が厳しくなる(上端や下端が交差するまで判定しない)
threshold: 0
};
// コールバック関数を用いて初期化
const io = new IntersectionObserver(cb, options);
console.log(io);
// 要素が複数あるためループで回して監視
els.forEach(el => io.observe(el));
console.log(els);
});
text-animation.jsの記述
//まず初めに<span class>文字</span>としたい、空白も表現したい
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)
// 上の3項演算子の元の記法
// if(el instanceof HTMLElement) {
// this.DOM.el = el;
// } else {
// this.DOM.el = document.querySelector(el);
// }
this.chars = this.DOM.el.innerHTML.trim().split("");
console.log(this.chars)
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
});
});
}
}
-
console.log(io);の中身でIntersectionObserverが呼ばれている。
-
console.log(els);の中身でDOM要素animate-titleがループ処理されたので3つ全て格納されている
- console.log(this.DOM.el)の中身で、3項演算子でelがDOMのときにはthis.Dom.elに格納してそうでないときは、querySelector(el);でDOMを取得して格納している。
-
console.log(this.chars)の中身で配列の中に加工前のものが入っている。
-
console.log(this.DOM.el.innerHTML)の中身で加工したあとの文字列が出力されている。
- 以下2番めのアニメーションで、3の部分の処理が行われている。
- 1番目と同じなので略
6.1に続きます