【问题标题】:Is there a callback for window.scrollTo?window.scrollTo 有回调吗?
【发布时间】:2019-02-16 22:38:03
【问题描述】:

我想在寡妇滚动后在输入上调用focus()。我正在使用scrollTo() 方法的平滑行为。问题是focus 方法削减了平滑行为。解决方案是在滚动结束后调用focus 函数。

但我找不到任何关于如何检测scrollTo 方法结束的文档或线程。

let el = document.getElementById('input')
let elScrollOffset = el.getBoundingClientRect().top
let scrollOffset = window.pageYOffset || document.documentElement.scrollTop
let padding = 12
window.scrollTo({
  top: elScrollOffset + scrollOffset - padding,
  behavior: 'smooth'
})
// wait for the end of scrolling and then
el.focus()

有什么想法吗?

【问题讨论】:

  • 我真的不知道scrollTo() 是否存在回调,但我认为只有知道滚动的持续时间才能尝试setTimeout()
  • 是的,我正在考虑,但我找不到 scrollTo 方法的滚动持续时间:/
  • 你可能想在使用你的hacky方法之前尝试this
  • @Akaino 谢谢你的提示,在原版中,我只会在 onscroll 监听器中工作并观察页面偏移量。远不及我正在做的事情。

标签: javascript


【解决方案1】:

我根据George Abitbol的方案写了一个泛型函数,没有覆盖window.onscroll:

/**
 * Native scrollTo with callback
 * @param offset - offset to scroll to
 * @param callback - callback function
 */
function scrollTo(offset, callback) {
    const fixedOffset = offset.toFixed();
    const onScroll = function () {
            if (window.pageYOffset.toFixed() === fixedOffset) {
                window.removeEventListener('scroll', onScroll)
                callback()
            }
        }

    window.addEventListener('scroll', onScroll)
    onScroll()
    window.scrollTo({
        top: offset,
        behavior: 'smooth'
    })
}

【讨论】:

  • 很棒的功能。不过,我认为你不需要在window.scrollTo 之前调用onScroll()
  • @caroso1222 谢谢!我在一些测试后补充说,因为如果滚动位置已经正确,回调将不会在没有该调用的情况下触发。
  • 偏移量必须是整数才能使此功能起作用
  • @btjakes 澄清一下:offset 需要完美匹配 window.pageYOffset。在 MS Edge 中,window.pageYOffset 是一个浮点数,与其他浏览器不同。由于跨浏览器的精度不匹配,除非您小心舍入并可能制作完成缓冲区,否则此方法将失败:if (roundedPageYOffset + 2 >= roundedOffset && roundedOffset >= roundedPageYOffset - 2) { ... },而不仅仅是if (window.pageYOffset === offset) { ... }
  • @btjakes 我修正了这个数字,所以浮点数不再是问题了。舍入是个好主意,但可能不够精确,具体取决于用例。
【解决方案2】:

我找到了一种方法来实现我想要的,但我认为这有点 hacky,不是吗?

let el = document.getElementById('input')
let elScrollOffset = el.getBoundingClientRect().top
let scrollOffset = window.pageYOffset || document.documentElement.scrollTop
let padding = 12
let target = elScrollOffset + scrollOffset - padding
window.scrollTo({
  top: target,
  behavior: 'smooth'
})
window.onscroll = e => {
  let currentScrollOffset = window.pageYOffset || document.documentElement.scrollTop
  // Scroll reach the target
  if (currentScrollOffset === target) {
    el.focus()
    window.onscroll = null // remove listener
  }
}

【讨论】:

    【解决方案3】:

    其他答案对我来说并不完全有效,因此基于@Fabian von Ellerts 的答案,我编写了自己的解决方案。

    我的问题是:

    • 我正在滚动的元素(以及它的所有父元素)的 offsetTop 始终为 0,因此它不起作用。

    • 我需要滚动一个嵌套元素。

    使用getBoundingClientRect 和容器元素作为参考作品:

        const smoothScrollTo = (
            scrollContainer,
            scrolledContent,
            offset,
            callback
        ) => {
            const fixedOffset = (
                scrollContainer.getBoundingClientRect().top + offset
            ).toFixed()
            const onScroll = () => {
                if (
                    scrolledContent.getBoundingClientRect().top.toFixed() ===
                    fixedOffset
                ) {
                    scrollContainer.removeEventListener('scroll', onScroll)
                    callback()
                }
            }
            scrollContainer.addEventListener('scroll', onScroll)
            onScroll()
            scrollContainer.scrollTo({
                top: offset,
                behavior: 'smooth',
            })
        }
    

    【讨论】:

      猜你喜欢
      • 2019-10-26
      • 1970-01-01
      • 2012-05-12
      • 1970-01-01
      • 2017-01-31
      • 2010-12-27
      • 2012-03-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多