element.scrollTo 和 element.scrollTop 在 Chrome 和 Firefox 的 window.requestAnimationFrame 循环中不起作用

问题描述

项目:我设置了一个滚动功能,当单击“向上”或“向下”时,它应该滚动到容器 div 中的下一个项目。它利用 window.requestAnimationFrame() 方法进行循环并在每次迭代时调用 element.scrollTo。

我这样做的原因是为了允许自定义持续时间,因为“行为:‘平滑’”设置是一个设定的速度,我想保留 css 滚动快照功能,因此它需要在容器内(所以 window.scrollTo() 是不可能的,尽管这似乎可以跨浏览器工作)。

问题:这在 Safari 中运行良好,但由于某种原因,.scrollTo() 函数没有在 Chrome 和 Firefox 中移动滚动视图。

我的尝试:

  1. 我尝试设置 element.scrollTop 而不是调用 element.scrollTo() 得到相同的结果。
  2. 我在某处读到 Chrome 的性能对于某些循环来说太快了,所以我用持续时间不同的 setTimeout(()=>{},1) 包围了 element.scrollTo()。这也不起作用。

我的代码代码可在 Codepen.io here

中查看

HTML:

<div class="scroll-wrap">
  <div id="item-1" class="scroll-item blue">
    <h1>1</h1>
    <div class="scroll-up"></div>
    <div class="scroll-down"></div>
  </div>
  <div id="item-2" class="scroll-item green">
    <h1>2</h1>
    <div class="scroll-up"></div>
    <div class="scroll-down"></div>
  </div>
  <div id="item-3" class="scroll-item red">
    <h1>3</h1>
    <div class="scroll-up"></div>
    <div class="scroll-down"></div>
  </div>
</div>

JS:

const scrollUps = document.querySelectorAll('.scroll-up')
const scrollDowns = document.querySelectorAll('.scroll-down')

// options...
options = {
  scrollWrap: document.querySelector('.scroll-wrap'),// scroll container.
  duration: 300,// Pixels per second. The smaller the number the longer the duration.
  easing: 'easeInOutSine',// can be eaSEOutSine,easeInOutSine,easeInOutQuint.
}

// RAF shim from ... http://www.paulirish.com/2011/requestanimationframe-for-smart-animating/
window.requestAnimFrame = (function(){
  return  window.requestAnimationFrame       ||
          window.webkitRequestAnimationFrame ||
          window.mozRequestAnimationFrame    ||
          function( callback ){
            window.setTimeout(callback,1000 / 60);
          };
})();

// Click Scroll function
function scrollToY(currentPosition,scrollTargetY) {
    // currentPostion: the current scrollY property of the view within the scroll container
    // scrollTargetY: the target scrollY property of the window
    // speed: time in pixels per second
    // easing: easing equation to use

var scrollY = currentPosition,scrollTargetY = scrollTargetY || 0,speed = options.duration || 2000,easing = options.easing || 'eaSEOutSine',currentTime = 0;

 // *For speed in pixels per second... 
 // min time .1,max time 5 seconds
var time = Math.max(.1,Math.min(Math.abs(scrollY - scrollTargetY) / speed,5));


// easing equations from https://github.com/danro/easing-js/blob/master/easing.js
const PI_D2 = Math.PI / 2,easingEquations = {
        eaSEOutSine: function (pos) {
            return Math.sin(pos * (Math.PI / 2));
        },easeInOutSine: function (pos) {
            return (-0.5 * (Math.cos(Math.PI * pos) - 1));
        },easeInOutQuint: function (pos) {
            if ((pos /= 0.5) < 1) {
                return 0.5 * Math.pow(pos,5);
            }
            return 0.5 * (Math.pow((pos - 2),5) + 2);
        }
    };

  // animation loop
  function tick() {
      currentTime += 1 / 60;

      const p = currentTime / time;
      const t = easingEquations[easing](p);

      if (p < 1) {
        requestAnimFrame(tick);
        const newPosition = scrollY + ((scrollTargetY - scrollY) * t)
        setTimeout(()=>{
          options.scrollWrap.scrollTo(0,newPosition);
          // console.log('scroll:',options.scrollWrap.scrollTop);
        },1)
        
        
      } else {
        // console.log('scroll done');
        options.scrollWrap.scrollTo(0,scrollTargetY);
      }
  }

  // call it once to get started
  tick();
}

// set clickable areas...
Array.from(scrollUps).forEach(btn => {
  btn.addEventListener('click',(e) => {
    // Get Parent of button...
    const parent = e.target.parentElement
    // Get destination element...
    const destId = `item-${Number(parent.id.split('-')[1]) - 1}`
    const dest = document.getElementById(destId)
    // call scroll function if destination exists...
    if(dest) {
      const destdistancetoTop = dest.offsetTop
      scrollToY(parent.offsetTop,destdistancetoTop)
    }
  })
})

Array.from(scrollDowns).forEach(btn => {
  btn.addEventListener('click',(e) => {
    const parent = e.target.parentElement
    const destId = `item-${Number(parent.id.split('-')[1]) + 1}`
    const dest = document.getElementById(destId)
    if(dest) {
      const destdistancetoTop = dest.offsetTop
      // console.log(destdistancetoTop,parent.offsetTop)
      scrollToY(parent.offsetTop,destdistancetoTop)
  
    }
  })
})

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...