Créer une directive de défilement personnalisée

Exemple de base

Plus d’une fois nous avons besoin d’introduire un comportement, en particulier d’animation, lors du défilement d’un site. Il y a plusieurs façons d’y parvenir mais le plus simple, en évitant d’accumuler les dépendances, est d’utiliser une Directive personnalisée pour créer un « hook » qui sera déclenché lors du défilement.

Vue.directive('scroll', {
inserted: function (el, binding) {
let f = function (evt) {
if (binding.value(evt, el)) {
window.removeEventListener('scroll', f)
}
}
window.addEventListener('scroll', f)
}
})

// main app
new Vue({
el: '#app',
methods: {
handleScroll: function (evt, el) {
if (window.scrollY > 50) {
el.setAttribute(
'style',
'opacity: 1; transform: translate3d(0, -10px, 0)'
)
}
return window.scrollY > 100
}
}
})
<div id="app">
<h1 class="centered">Faites-moi défiler</h1>
<div
v-scroll="handleScroll"
class="box"
>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. A atque amet harum aut ab veritatis earum porro praesentium ut corporis. Quasi provident dolorem officia iure fugiat, eius mollitia sequi quisquam.</p>
</div>
</div>

N’oubliez pas ! La directive doit être enregistrée avant la création de l’instance de Vue.

Nous avons également besoin d’une propriété pour calculer les valeurs intermédiaires lors de la transition, dans notre cas :

.box {
transition: 1.5s all cubic-bezier(0.39, 0.575, 0.565, 1);
}

See the Pen Custom Scroll Directive- CSS Transition by Sarah Drasner (@sdras) on CodePen.

Ou, avec GreenSock(GSAP) ou toute autre librairie d’animation JavaScript, le code devient encore plus simple :

Vue.directive('scroll', {
inserted: function (el, binding) {
let f = function (evt) {
if (binding.value(evt, el)) {
window.removeEventListener('scroll', f)
}
}
window.addEventListener('scroll', f)
}
})

// main app
new Vue({
el: '#app',
methods: {
handleScroll: function (evt, el) {
if (window.scrollY > 50) {
TweenMax.to(el, 1.5, {
y: -10,
opacity: 1,
ease: Sine.easeOut
})
}
return window.scrollY > 100
}
}
})

Nous devons retirer la transition CSS de l’exemple précédent puisque dans cette implémentation, tout est calculé directement avec JavaScript.

Le bénéfice de l’utilisation des directives personnalisées

Vue est riche en option pour les directives, ce qui permet de couvrir la majorité des cas d’utilisation, ce qui permet d’améliorer la production et l’expérience de développement. Mais pour certains « cas limite » qui ne seraient pas couverts par le framework, ce sera à vous de réaliser la directive qui répondra parfaitement à vos besoins.

Ajouter et retirer des « évènements de défilement/scroll » sur un élément est un bon cas d’utilisation de cette technique, parce qu’à l’image des autres directives, elle est nécessairement liée à un élément sinon, il faudrait trouver l’élément dans le DOM. Ce modèle évite d’avoir besoin de parcourir le DOM et conserve une logique évènementielle avec le noeud auquel il fait référence.

Exemple concret : Utiliser une directive de défilement personnalisée pour animer en cascade

Au cours de la création de vos sites, vous constaterez que vous réutilisez régulièrement les mêmes logiques d’animation à plusieurs endroits. C’est simple, nous allons créer une directive super spécifique ? Et bien, typiquement si nous souhaitons pouvoir la réutiliser, nous devons la rendre légèrement personnalisable pour chaque cas d’utilisation.

Afin de conserver un code concis et lisible, nous allons transmettre des arguments prédéfinis, tels que le point de départ et de fin d’animation au fur et à mesure que nous parcourons la page.

Cet exemple est plus visuel en plein écran.

See the Pen Scrolling Example- Using Custom Directives in Vue by Sarah Drasner (@sdras) on CodePen.

Dans la démo ci-dessus, chacune des sections comporte deux différents types d’animations déclenchés lors du défilement : Une animation type « morphing » et une animation type « dessin » qui anime individuellement chacun des <path> du SVG. Réutilisons ces deux animation pour créer une directive personnalisée pour chaqu’un des cas. Les arguments qui seront transmis vont nous aider à garder l’ensemble simple et réutilisable.

Pour analyser l’exemple de l’animation « morphing », nous aurons besoin d’indiquer ou l’animation commence et termine ainsi que la valeur du <path> qui va permettre le calcul du morphing. Ces arguments sont définis via binding.value.foo :

Vue.directive('clipscroll', {
inserted: function (el, binding) {
let f = function (evt) {
var hasRun = false
if (!hasRun && window.scrollY > binding.value.start) {
hasRun = true
TweenMax.to(el, 2, {
morphSVG: binding.value.toPath,
ease: Sine.easeIn
})
}
if (window.scrollY > binding.value.end) {
window.removeEventListener('scroll', f)
}
}
window.addEventListener('scroll', f)
}
})

Nous pouvons alors utiliser cette animation directement dans le <template>, en attachant la directive à l’élément <path> tout en transmettant les arguments de la directive dans un Object

<clipPath id="clip-path">
<path
v-clipscroll="{ start: '50', end: '100', toPath: 'M0.39 0.34H15.99V22.44H0.39z' }"
id="poly-shapemorph"
d="M12.46 20.76L7.34 22.04 3.67 18.25 5.12 13.18 10.24 11.9 13.91 15.69 12.46 20.76z"
/>
</clipPath>

Alternative

Les directives personnalisées sont extrêmement utiles, mais vous pouvez trouver des situations dans lesquelles vous aurez besoin de quelque chose de très spécifique, qui existe déjà dans des librairies de défilement et que vous ne souhaitez pas réécrire totalement vous-même.

Scrollmagic est doté d’un écosysteme très riche, une très bonne documentation ainsi que des démos à explorer. Cela inclus de façon non exhaustive, des cas comme l’effet parallax, Épingler en cascade, Recouvrement de section, et responsive duration.