ウェブサイトをつくるとき、スクロールして画面に入ったらアニメーションをする
といったことがよくあると思います。
Vue.jsでウェブサイトをつくることが多くなってきたので、なにか便利な方法ないかと
検討した結果、この記事で紹介する方法がシンプルでいいかなと思ったのでご紹介します。
scrollmagicに関して
srocll連動でアニメーションをさせる系のライブラリでscrollmagicという
ライブラリがあります。以前のjqueryとかでやっていた制作環境で重宝していたのですが、
Vue.js環境でもうまいこと使う方法はないかと模索してみたという感じです。
(jquery依存はしていないライブラリですしね!)
ライブラリの細かな説明はしませんので各自ググってみてください。
exampleが充実しているので困ることはないと思います。
本題
プラグインの作成
scrollmagicの仕様上、Vue.use()で使えるようになるプラグインとして
使うのがいいかなと思い、プラグインというほど大げさなものではないですが
プラグインの作成から始めてみたいと思います。
適当なディレクトリに以下のようなjsファイルを作成します。
(vue-scrollmagic/index.js
とか)
export default {
install (Vue, options = {}) {
const { global = true} = options
if (typeof window !== 'undefined' && typeof document !== 'undefined') {
const ScrollMagic = require('scrollmagic')
Vue.mixin({
computed: {
$smController() { return new ScrollMagic.Controller() },
$sm() { return ScrollMagic }
}
})
}
}
}
プラグインに関する細かい話はドキュメント等を見ていただくとして、
やっていることはシンプルでmixinでcomputedにscrollmagicのコントローラーを追加しているだけです。
(一応ライブラリ全体も)
globalというオプションを渡していますがこちらについては後述します。
controllerはアプリケーション内に1つあればいいのでこういう実装にしてみました。
イベントコンポーネントの作成
この記事の肝になってくるところですが、画面内に入った/出たらイベントを発行してくれるだけの
機能を持ったコンポーネントを作成して、アニメーションをさせたいコンポーネントで使う。
ということにしました。文字では微妙に伝わりにくいかと思いますのでとりあえず実装をみてみましょう。
(vue-scrollmagic/SMEvent.vue
とかつくります)
<template>
<div></div>
</template>
<script>
export default {
props:{
triggerHook:{
type: [Number, String],
default: "onEnter",
},
offset:{
type: [Number],
default: 0
},
},
components: {},
computed: {},
methods: {
onEnter(){
this.$emit('onEnter')
},
},
mounted () {
this.scene = new this.$sm.Scene({
triggerElement: this.$el,
})
this.scene.on('enter', this.onEnter)
this.scene.triggerHook(this.triggerHook)
this.scene.offset(this.offset)
this.$smController.addScene(this.scene);
},
beforeDestory(){
this.$smController.removeScene(this.scene)
this.scene.off('enter', this.onEnter)
this.scene = this.scene.destory(true)
},
watch: {
offset: function(next){
this.scene.offset(next);
},
triggerHook: function(next){
this.scene.triggerHook(next);
}
}
}
</script>
<style scoped>
</style>
このコンポーネントは一例似すぎないのですが、(propsで渡すoption、発行するイベント等)
今回は"Enter"のイベントをemitする、指定できるオプションはtriggerHook(イベントが発生する位置)と
offset(発生する位置のオフセット)のみとするコンポーネントを作成しました。
beforeDestoryで消す処理をいれたり、watch関数を使ってオプションが変わったときに
設定し直すとかしてますが(Vueはこういうところがべんり!)やっていることはシンプルなはずです。
もしかしたらまだピンときていないかもしれませんが次にこれの使い方を説明します。
イベントコンポーネントの使用
使用する前に一度プラグインのファイルに戻って以下のようにします。
(install関数内のみ抜粋、1番上にimport SMEvent from './SMEvent'
を書く)
const { global = true} = options
if (typeof window !== 'undefined' && typeof document !== 'undefined') {
const ScrollMagic = require('scrollmagic')
Vue.mixin({
computed: {
$smController() { return new ScrollMagic.Controller() },
$sm() { return ScrollMagic }
}
})
}
//新しく追加
if (global) {
Vue.component('sm-event', SMEvent)
}
Vueコンポーネントをグローバルにしてどのコンポーネントでもmodulesで指定しなくても
使えるようにしました。Vue.use()のoptionに{global: false}
(defaultはtrue)
を渡せばグローバルではなくなるようにしています。
さて、使用してみる話からは少しはずれましたがスクロール連動アニメーションを
伴う適当なコンポーネントを作成してみます。画面内の中央にきたらフェードインするだけにしました。
Vue.use()されている想定です。
<template lang="pug">
.root
sm-event(triggerHook="onCenter" @onEnter="onEnter" :offset="0")
p(ref="fadeText") フェードするテキストです。
</template>
<script>
export default {
methods: {
onEnter(){
this.$refs.fadeText.classList.add('active');
}
},
}
</script>
<style lang="stylus" scoped>
p
opacity 0
transition opacity 1s ease 0s
p.active
opacity 1
</style>
自分でつくったものを簡略化して雰囲気で書き直して動作検証してないので
動作するかはわかりませんがおそらくこれで動くかなというものです。
em-event
コンポーネントの@onEnter
でイベントを受け取るメソッドを
指定してonEnter内でrefs使って'active'というclassを追加してみます。
アニメーションはcss(stylus)に書いてみました。
SMEventをコンポーネント内に追加して受け取るメソッド名をすれば
任意のコンポーネントでスクロール連動の演出が作りたい放題ですね!
また今回は簡単にすべくclassを付与してcssアニメーションにしましたが、
TweenMaxを使ってもいいしなんでもできそうです。
SMEventの方も、今回はEnterイベントのみでしたが別のイベントを発行する
ようにしてもいいし、別のコンポーネントをつくってもいいので好きに拡張していけると思います。
以上、現時点で自分が思う、Vue.jsでのスクロール演出つくりかたでした。
ここまで読んでくれた方ありがとうございます。