734

0

ScrollTrigger

让您的页面对滚动做出反应。

ScrollTrigger

建造 部署 执照 问题 GitHub 发布 npm(范围)

让您的页面对滚动更改做出反应。

ScrollTrigger 最基本的用法是根据当前滚动位置触发类。例如,当元素进入视口时,将其淡入。您可以为每个元素添加自定义偏移量,或在视口上设置偏移量(例如,始终在元素达到视口的 20% 后触发)

当使用回调时,ScrollTrigger 变得非常强大。您可以在元素进入/变得可见时运行自定义代码,甚至在回调失败时返回 Promises 以停止触发器。这使得延迟加载图像非常容易。

安装

npm install @terwanerik/scrolltrigger或者只是将 dist/ScrollTrigger.min.js文件添加到您的项目中并导入它。

如何使用?

最简单的开始方法是创建一个新实例并向其中添加一些触发器,并使用所有默认值。这将在元素进入视口时切换“可见”类,并在元素滚动出视口时切换“不可见”类。

// when using ES6 import / npm
import ScrollTrigger from '@terwanerik/scrolltrigger'
// Create a new ScrollTrigger instance with default options
const trigger = new ScrollTrigger() // When not using npm, create a new instance with 'new ScrollTrigger.default()'
// Add all html elements with attribute data-trigger
trigger.add('[data-trigger]')

现在在您的 CSS 中添加以下类,这会使 [data-trigger]元素淡入淡出。

.visible, .invisible {
  opacity: 0.0;
  transition: opacity 0.5s ease;
}
.visible {
  opacity: 1.0;
}

⚠️ 注意 您是否正在从 0.x 迁移到 1.x?查看迁移指南!

还有一些演示

一个更详细的例子

添加回调/不同的类可以全局完成,这将成为您添加的所有触发器的默认设置,或者您可以在添加触发器时指定自定义配置。

// Create a new ScrollTrigger instance with some custom options
const trigger = new ScrollTrigger({
  trigger: {
    once: true
  }
})
// Add all html elements with attribute data-trigger, these elements will only be triggered once
trigger.add('[data-trigger]')
// Add all html elements with attribute data-triggerAlways, these elements will always be triggered
trigger.add('[data-triggerAlways]', { once: false })

选项

完整的选项集取自 demo目录,有关更多信息,请查看。

const trigger = new ScrollTrigger({
    // Set custom (default) options for the triggers, these can be overwritten
    // when adding new triggers to the ScrollTrigger instance. If you pass
    // options when adding new triggers, you'll only need to pass the object
    // `trigger`, e.g. { once: false }
    trigger: {
        // If the trigger should just work one time
        once: false,
        offset: {
            // Set an offset based on the elements position, returning an
            // integer = offset in px, float = offset in percentage of either
            // width (when setting the x offset) or height (when setting y)
            //
            // So setting an yOffset of 0.2 means 20% of the elements height,
            // the callback / class will be toggled when the element is 20%
            // in the viewport.
            element: {
                x: 0,
                y: (trigger, rect, direction) => {
                    // You can add custom offsets according to callbacks, you
                    // get passed the trigger, rect (DOMRect) and the scroll
                    // direction, a string of either top, left, right or
                    // bottom.
                    return 0.2
                }
            },
            // Setting an offset of 0.2 on the viewport means the trigger
            // will be called when the element is 20% in the viewport. So if
            // your screen is 1200x600px, the trigger will be called when the
            // user has scrolled for 120px.
            viewport: {
                x: 0,
                y: (trigger, frame, direction) => {
                    // We check if the trigger is visible, if so, the offset
                    // on the viewport is 0, otherwise it's 20% of the height
                    // of the viewport. This causes the triggers to animate
                    // 'on screen' when the element is in the viewport, but
                    // don't trigger the 'out' class until the element is out
                    // of the viewport.

                    // This is the same as returning Math.ceil(0.2 * frame.h)
                    return trigger.visible ? 0 : 0.2
                }
            }
        },
        toggle: {
            // The class(es) that should be toggled
            class: {
                in: 'visible', // Either a string, or an array of strings
                out: ['invisible', 'extraClassToToggleWhenHidden']
            },
            callback: {
                // A callback when the element is going in the viewport, you can
                // return a Promise here, the trigger will not be called until
                // the promise resolves.
                in: null,
                // A callback when the element is visible on screen, keeps
                // on triggering for as long as 'sustain' is set
                visible: null,
                // A callback when the element is going out of the viewport.
                // You can also return a promise here, like in the 'in' callback.
                //
                // Here an example where all triggers take 10ms to trigger
                // the 'out' class.
                out: (trigger) => {
                    // `trigger` contains the Trigger object that goes out
                    // of the viewport
                    return new Promise((resolve, reject) => {
                        setTimeout(resolve, 10)
                    })
                }
            }
        },
    },
    // Set custom options and callbacks for the ScrollAnimationLoop
    scroll: {
        // The amount of ms the scroll loop should keep triggering after the
        // scrolling has stopped. This is sometimes nice for canvas
        // animations.
        sustain: 200,
        // Window|HTMLDocument|HTMLElement to check for scroll events
        element: window,
        // Add a callback when the user has scrolled, keeps on triggering for
        // as long as the sustain is set to do
        callback: didScroll,
        // Callback when the user started scrolling
        start: () => {},
        // Callback when the user stopped scrolling
        stop: () => {},
        // Callback when the user changes direction in scrolling
        directionChange: () => {}
    }
})

/***
 ** Methods on the ScrollTrigger instance
 ***/

/**
 * Creates a Trigger object from a given element and optional option set
 * @param {HTMLElement} element
 * @param {DefaultOptions.trigger} [options=DefaultOptions.trigger] options
 * @returns Trigger
 */
trigger.createTrigger(element, options)

/**
 * Creates an array of triggers
 * @param {HTMLElement[]|NodeList} elements
 * @param {Object} [options=null] options
 * @returns {Trigger[]} Array of triggers
 */
trigger.createTriggers(elements, options)

/**
 * Adds triggers
 * @param {string|HTMLElement|NodeList|Trigger|Trigger[]} objects A list of objects or a query
 * @param {Object} [options=null] options
 * @returns {ScrollTrigger}
 */
trigger.add(objects, options)

/**
 * Removes triggers
 * @param {string|HTMLElement|NodeList|Trigger|Trigger[]} objects A list of objects or a query
 * @returns {ScrollTrigger}
 */
trigger.remove(objects)

/**
 * Lookup one or multiple triggers by a query string
 * @param {string} selector
 * @returns {Trigger[]}
 */
trigger.query(selector)

/**
 * Lookup one or multiple triggers by a certain HTMLElement or NodeList
 * @param {HTMLElement|HTMLElement[]|NodeList} element
 * @returns {Trigger|Trigger[]|null}
 */
trigger.search(element)

/**
 * Reattaches the scroll listener
 */
trigger.listen()

/**
 * Kills the scroll listener
 */
trigger.kill()


/***
 ** Methods on a Trigger instance, e.g. when receiving from a callback or from a query
 ***/
const receivedTrigger = new Trigger()

/**
 * The HTML element
 */
receivedTrigger.element

/**
 * The offset settings
 */
receivedTrigger.offset

/**
 * The toggle settings
 */
receivedTrigger.toggle

/**
 * If the trigger should fire once, boolean
 */
receivedTrigger.once

/**
 * If the trigger is visible, boolean
 */
receivedTrigger.visible

从 0.x 迁移到 1.x

0.x和之间的主要区别在于 1.x您添加和配置触发器的方式。0.x默认情况下添加所有带有 data-scroll 属性的 HTMLElement, 1.x不这样做,这需要您自己添加触发器。这改进了触发器的配置。

另外,请注意,当使用包管理器/webpack 时,您只是导入缩小版本,您必须始终使用 new ScrollTrigger.default().

<script src="dist/ScrollTrigger.min.js"></script>
<script>
var trigger = new ScrollTrigger.default()
</script>

以 ScrollTrigger 中的以下元素为例 0.x

<div data-scroll="once addHeight" data-scroll-showCallback="alert('Visible')" data-scroll-hideCallback="alert('Invisible')"></div>

在 ScrollTrigger 中 1.x,您主要使用 JavaScript 编写:

// Say you have some divs with class 'animateMe'
const scrollTrigger = new ScrollTrigger()
scrollTrigger.add('.animateMe', {
    once: true, // same functionality as the `once` flag in v0.x
    offset: {
        element: {
            y: 1.0 // note that we pass a float instead of an integer, when the
                   // offset is a float, it takes it as a percentage, in this
                   // case, add 100% of the height of the element, the same
                   // functionality as the `addHeight` flag in v0.x
        }
    },
    toggle: {
        callback: {
            in: () => { // same as the data-scroll-showCallback, no need to set a
                        // custom callScope when calling custom functions and
                        // the possibility to return a Promise
                alert('Visible')
            },
            out: () => { // same as the data-scroll-hideCallback
                alert('Invisible')
            }
        }
    }
})

用 javascript 编写所有这些的好处是可以进行配置,比如我想在元素第一次可见后更改元素的偏移量(例如,addHeight在显示后删除标志):

scrollTrigger.add('.animateMe', {
    offset: {
        element: {
            y: 1.0
        }
    },
    toggle: {
        callback: {
            in: (trigger) => {
                // remove the element offset
                trigger.offset.element.y = 0
            }
        }
    }
})

为每个切换设置自定义类的另一个示例;

<div data-scroll="toggle(animateIn, animateOut)"></div>

变成

const scrollTrigger = new ScrollTrigger()

scrollTrigger.add('[data-scroll]', {
    toggle: {
        class: {
            in: 'animateIn',
            out: 'animateOut'
        }
    }
})

如果您对迁移有任何疑问,请 v1.x随时创建一个新问题

贡献

叉子,看看 src/目录,享受吧!如果您有改进,请在完成后创建一个新分支并创建一个拉取请求:)

故障排除

通过点击“检查元素”,您可以非常快速地查看触发器是否正在工作。在这里,您可以查看滚动过去元素时是否切换了可见/不可见类。

如果类没有切换,请检查 JavaScript 控制台。里面可能有一些方便的信息。

发现问题?

哦,快,好吧,错误发生了。请创建一个新问题并提及出现问题的操作系统和浏览器(包括版本)。如果您真的很友善,请制作一个最小、完整且可验证的示例并将其上传到codepen

遗产

寻找旧的 ScrollTrigger?查看遗留分支