Close
升级到 Vue 3 | Vue 2 EOL

创建自定义滚动指令

基本示例

在很多情况下,我们可能希望为网站上的滚动事件添加一些行为,尤其是动画。有很多方法可以做到这一点,但代码和依赖项最少的路径可能是使用 自定义指令 来创建一个钩子,用于触发特定滚动事件的任何内容。

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">Scroll me</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);
}

查看 CodePen 上 Sarah Drasner 的 自定义滚动指令 - CSS 过渡

或者,使用 GreenSock(GSAP) 或任何其他 JavaScript 动画库,代码变得更加简单

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
}
}
})

尽管我们会从这个实现中删除之前的 CSS 过渡,因为它现在由 JavaScript 处理。

使用自定义指令的好处

Vue 拥有丰富的指令选项,其中大多数涵盖了非常常见的用例,这可以创造非常高效的开发体验。但即使你有一个框架没有涵盖的边缘情况,它也能满足你的需求,因为你可以很容易地创建一个自定义指令来满足你的需求。

将滚动事件附加到元素并从元素中移除,是使用这种技术的非常好的用例,因为就像我们使用的其他指令一样,它们必然与元素绑定,否则,我们必须在 DOM 中找到它的引用。这种模式避免了遍历的需要,并将事件逻辑与它所引用的节点配对。

现实世界示例:使用自定义滚动指令进行级联动画

在创建一致的网站的过程中,你可能会发现你在多个区域重复使用相同的动画逻辑。这似乎很简单,那么我们就会创建一个非常具体的自定义指令,对吧?好吧,通常如果你重复使用它,你需要为每次使用稍微修改它。

为了帮助保持代码简洁易读,我们希望传入一些预定义的参数,例如动画的开始点和结束点,因为我们向下滚动页面。

这个例子在 全屏版本 中效果更好。

查看 CodePen 上 Sarah Drasner 的 滚动示例 - 在 Vue 中使用自定义指令

在上面的演示中,每个部分都有两种不同的动画类型,它们由滚动触发:变形动画和绘制动画,它会动画化 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 拥有非常丰富的生态系统,以及良好的文档和演示供你探索。这包括但不限于诸如 视差级联固定部分擦除响应式持续时间