Часто случается, что нам необходимо добавить какое-нибудь нестандартное поведение, например анимацию, при прокрутке на сайте. Существует много способов, как реализовать подобное, но способ, требующий меньше всего кода и зависимостей, заключается в использовании пользовательской директивы для создания перехватчика, который срабатывает при определённом событии прокрутки.
Vue.directive('scroll', {
inserted: function (el, binding) {
let f = function (evt) {
if (binding.value(evt, el)) {
window.removeEventListener('scroll', f)
}
}
window.addEventListener('scroll', f)
}
})
// основное приложение
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">Прокрути меня</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>
Важно! Директива должна быть зарегистрирована до экземпляра Vue.
Также нам понадобится свойство в стилях, которое позволит сделать переход между промежуточными состояниями более плавным:
.box {
transition: 1.5s all cubic-bezier(0.39, 0.575, 0.565, 1);
}
Посмотреть примерПользовательская директива прокрутки - CSS переходы от Sarah Drasner (@sdras) на CodePen.
С помощью GreenSock или любой другой JS-библиотеки для анимаций, можно упростить код:
Vue.directive('scroll', {
inserted: function (el, binding) {
let f = function (evt) {
if (binding.value(evt, el)) {
window.removeEventListener('scroll', f)
}
}
window.addEventListener('scroll', f)
}
})
// основное приложение
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
}
}
})
Мы удалим предыдущее CSS-свойство transition из этого решения, так как теперь плавность перехода управляется с помощью JavaScript.
Vue богат различными настройками для директив, многие из которых решают большинство задач, что положительно сказывается на процессе разработки. Но даже если у вас есть частный случай, который не покрывается стандартными средствами каркаса, он может быть легко решён с помощью создания пользовательской директивы, соответствующей вашим требованиям.
Добавление и удаление обработчиков на события прокрутки элементов — это действительно хорошее использование данной техники, потому, что директивы прокрутки всегда связаны с самим элементом. В противном случае нам пришлось бы искать ссылку на соответствующий элемент в DOM. Данный подход избавляет от необходимости прохода по DOM, и держит логику события связанной с узлом, на который оно ссылается.
В процессе создания связующего сайта вы можете обнаружить, что переиспользуете один и тот же тип анимаций в нескольких областях. Это кажется простым — создать весьма конкретную пользовательскую директиву, не так ли? Обычно, если вы её переиспользуете, вам понадобится её просто слегка изменить при каждом использовании.
Чтобы оставить наш код лаконичным и понятным, мы бы захотели передать некоторые параметры, такие, как начальная и конечная точки анимации во время прокрутки страницы вниз.
Этот пример лучше просматривать в полноэкранной версии.
Посмотреть пример Пример с прокруткой - Использование пользовательской директивы во Vue от Sarah Drasner (@sdras) на CodePen.
В примере выше каждая секция имеет два типа анимаций, которые срабатывают во время прокрутки: анимация изменения формы и анимация отрисовки, которая анимирует отдельные пути в SVG. Мы переиспользуем обе, так что мы можем написать пользовательские директивы для каждой из них. Аргументы, которые мы передадим внутрь, помогут сохранить простоту и универсальность.
Чтобы показать, как это делается, мы рассмотрим пример с изменением формы, где нам нужно указать значения пуска и окончания анимации, а также передать значение пути, в который мы будем превращать форму. Эти аргументы определяются как 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)
}
})
После этого, мы можем использовать эту анимацию в нашем шаблоне. В данном случае мы привязываем директиву к элементу clipPath
и передаём все наши аргументы внутри объекта в директиву.
<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>
Пользовательские директивы очень полезны, но у вас может возникнуть ситуация, когда вам понадобится что-то очень специфичное, но уже реализованное в библиотеках для прокрутки страницы, и у вас не будет желания писать это с нуля.
Scrollmagic обладает очень богатой экосистемой для работы, так же, как и хорошей документацией с примерами. Он включает в себя, но не ограничивается такими возможностями, как параллакс-эффект, каскадное закрепление, вытеснение областей и отзывчивая продолжительность анимации.