Vue.js:サイトの背景をMacのスクリーンセーバーみたいにする方法

##Macの「アレ」を再現したい。
Macのスクリーンセーバーで、写真とかループして見せるアレ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216132/2f21a5f2-376b-069d-e570-e376871594d2.png)

Macのスクリーンセーバーとか、おしゃれサイトによくある、
背景一面に画像が敷かれていて、その画像がゆっくりフワ〜っと拡大したりしてて、
しかも数枚の画像がフェードイン、アウトで切り替わって行くやつ。

あれできないかな〜と思って色々探してて、調べたらできたのでメモしておく。
書きながら反芻して覚えてるので微妙に間違ってるかもです。

##今回はVue.js
今回は`Vue.js`で作りましたが、他にも応用が効くと思います。

```App.vue
<template>
  <div id="app">
    <div class="container">
      <div class="slides">
        <div class="slide slide-1"></div>
        <div class="slide slide-2"></div>
        <div class="slide slide-3"></div>
      </div>
    </div>
  </div>
</template>
```
```App.vue.scss
<style lang="scss" scoped>
.container {
  width: 100%;
  height: 100vh;
  position: relative;
  overflow: hidden;
}
.slides {
  //background-position: center;
  //background-size: cover;
}
.slide {
  position: absolute;
  width: 100%;
  height: 100vh;
  background-size: cover;
  &.slide-1 {
    background-image:url('/images/top/image1.jpg');
  }
  &.slide-2 {
    background-image:url('/images/top/image2.jpg');
  }
  &.slide-3 {
    background-image:url('/images/top/image3.jpg');
  }
}
</style>
```
ココまでは至って普通です。というか`transition`もないので、
シンプルなCSSです。

##JSはちょっとややこしい。
JSの部分は解説用に、細切れにして説明します。
まずは`gsap`と`jquery`読み込んでおきます。
※」`jquery`は`DOM`を指定するだけに使ってます。

```App.vue.js
<script>
//import { TimeLineMax, Power0 } from 'gsap'　←古い
import gsap, {Power0} from 'gsap'
import $ from 'jquery'
//（以下略）
```
今回はDOMの操作なので、`mounted`に書いていきます。

```App.vue.js
export default {
  mounted(){
    //ココに書いていきます。
  },
//（以下略）
```
下記のように、初期設定のパラメータを用意します。

```App.vue.js
var slides = $(".slide"), //←動かすDOM自身
    duration = 5,         //←表示させておく秒数
    overlap = 2,          //←何秒重ねておくか
    left = 5,             //x軸のズラし
    scale = 1.15;         //拡大率
```
「x軸のズラシって何だよ？必要か？」と思うじゃないですか。
これ今は固定ですけど、「ランダム」とか「y軸」を入れることで、
スライドごとに「変化球」ができるようになり、若干有機的な動きになります、多分。

` gsap.timeline`を初期化する。このプラグインについてはよく理解してないですが、
名前からして「タイムライン通りにアニメーションしてくれる」的な意味と思います。
で、完了したら`repeatFunction`を実行するような書き方。

```App.vue.js
var tl = new gsap.timeline({onComplete:repeatFunction});
```
```App.vue.js
function repeatFunction() {
  tl.play("repeat")
}
```
最初は複数枚ある→`$(".slide")`をセットします。
`:gt(0)`=「slide要素の1番最初」に、不透明度「0」を設定しておきます。

```App.vue.js
tl.set(slides.filter(":gt(0)"), {autoAlpha:0});
```
次に、この画像が、どうアニメーションするかを`to`で決めます。
`duration`は先程初期設定で、5秒に設定しました。
`x軸`は先程初期設定で`5`足すように設定しました。
「拡大率」`scale`は先程初期設定で`1.15`倍に設定しました。
「イージング」`ease`は、`Power0.easeInOut`に。

`Power0`ってなんだ？と思ったんですが、
イージング機能のアップグレード版みたいなものだと思います。

```App.vue.js
tl.to(slides[0], duration, {x: "+=" + left, scale: scale, ease: Power0.easeInOut})
```
最初の画像がアニメーションした所に、リピートのポイントを追加します。
`tl.play("repeat")`で、ココから再開するようです。

```App.vue.js
.add("repeat")
```
次の画像と`2秒`オーバーラップします。

```App.vue.js
.to(slides[1], overlap, {autoAlpha: 1})
```
オーバーラップの2秒をマイナスして、同様のアニメーションをします。

```App.vue.js
.to(slides[1], duration, {x: "+=" + left, scale: scale, ease: Power0.easeInOut}, "-=" + overlap)
```
３番目も同様にアニメーションさせます。

```App.vue.js
.to(slides[2], overlap, {autoAlpha: 1})
.to(slides[2], duration, {x: "+=" + left, scale: scale, ease: Power0.easeInOut}, "-=" + overlap)
```
１番最初の画像は動かし切ってしまったので、初期状態に戻します。

```App.vue.js
.set(slides[0], {zIndex:8, scale:1, x:0, autoAlpha:0})
```
そして他の画像と同様に、アニメーションさせていく。

```App.vue.js
.to(slides[0], overlap, {autoAlpha: 1})
.to(slides[0], duration, {x: "+=" + left, scale: scale, ease: Power0.easeInOut}, "-=" + overlap)
```
ここでアニメーションのタイムラインが終わるので、`repeat`の部分から繰り返すようになります。
全部をつなげると、こうなります。

```App.vue.js
<script>
import gsap,{Power0} from 'gsap'
import $ from 'jquery';
export default {
  name: 'App',
  mounted(){
    var slides = $(".slide"),
    duration = 5,
    overlap = 2,
    left = 5,
    scale = 1.15;

    var tl = new gsap.timeline({onComplete:repeatFunction});
    tl.set(slides.filter(":gt(0)"), {autoAlpha:0});

    tl.to(slides[0], duration, {x: "+=" + left, scale: scale, ease: Power0.easeInOut})
      .add("repeat")
      .to(slides[1], overlap, {autoAlpha: 1})
      .to(slides[1], duration, {x: "+=" + left, scale: scale, ease: Power0.easeInOut}, "-=" + overlap)
      .to(slides[2], overlap, {autoAlpha: 1})
      .to(slides[2], duration, {x: "+=" + left, scale: scale, ease: Power0.easeInOut}, "-=" + overlap)
      .set(slides[0], {zIndex:8, scale:1, x:0, autoAlpha:0})
      .to(slides[0], overlap, {autoAlpha: 1})
      .to(slides[0], duration, {x: "+=" + left, scale: scale, ease: Power0.easeInOut}, "-=" + overlap)
    function repeatFunction() {
      tl.play("repeat")
    }
  },
}
</script>
```

これで背景を作っておけば、最近のウェブサイトでよくある
背景一面になんかフワ〜っと動いてるスライドショー的な画像が敷かれてるヤツができます。

![66bbdc10bc1c316db229798940c8122b_2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216132/1aa2c4fa-3736-e133-32e4-6a58c8626d2d.gif)

いやはや…最初は`Swiper`を改造して作ろうとしてハマりました。
`gsap`のアニメーション機能が、すごく良いです。

あと変な書き方していて、ビルドしたら動かなくなるという罠があり、見事に引っかかりました。
こちらの方の記事を参考に書き直しました。
https://qiita.com/mksm_wrk/items/ba5feb0baf1d8e8703e2


##参考資料
https://greensock.com/forums/topic/21532-module-warning-from-node_modulesvuecli-plugin-eslintnode_moduleseslint-loaderindexjs-error-power0-is-not-defined-no-undef/
https://qiita.com/mksm_wrk/items/ba5feb0baf1d8e8703e2
https://codepen.io/rreyes/pen/JJYRNJ
https://greensock.com/3/
https://greensock.com/3-release-notes
https://greensock.com/docs/v2/Easing/Power0
https://greensock.com/docs/v2/Easing