香草javascript中鼠标滚轮上的平滑垂直滚动?

Posted

技术标签:

【中文标题】香草javascript中鼠标滚轮上的平滑垂直滚动?【英文标题】:Smooth vertical scrolling on mouse wheel in vanilla javascript? 【发布时间】:2018-04-11 04:26:28 【问题描述】:

我是 vanilla javascript 的忠实粉丝,目前我正在做一个项目,我需要在鼠标滚轮滚动上实现平滑滚动。我想使用 vanilla JS 来实现它。 我在做一些研究时发现了一个 jQuery sn-p,如下所示。

$(window).on('mousewheel DOMMouseScroll', function(e) 
   var dir,
   amt = 100;

   e.preventDefault();
   if(e.type === 'mousewheel') 
     dir = e.originalEvent.wheelDelta > 0 ? '-=' : '+=';
   
   else 
     dir = e.originalEvent.detail < 0 ? '-=' : '+=';
         

   $('html, body').stop().animate(
     scrollTop: dir + amt
   ,500, 'linear');
);

任何人都可以帮助我,例如如何在不使用 jQuery 或任何其他库之类的辅助库的情况下实现平滑滚动。

人们已经在 jQuery 中完成了许多实现。但我想要一个可以在 vanilla JS 中实现的最佳实现。这可以在任何地方的 React、Angular 和 Vue 中的任何地方实现。

【问题讨论】:

【参考方案1】:

这个怎么样:

function init()
	new SmoothScroll(document,120,12)


function SmoothScroll(target, speed, smooth) 
	if (target === document)
		target = (document.scrollingElement 
              || document.documentElement 
              || document.body.parentNode 
              || document.body) // cross browser support for document scrolling
      
	var moving = false
	var pos = target.scrollTop
  var frame = target === document.body 
              && document.documentElement 
              ? document.documentElement 
              : target // safari is the new IE
  
	target.addEventListener('mousewheel', scrolled,  passive: false )
	target.addEventListener('DOMMouseScroll', scrolled,  passive: false )

	function scrolled(e) 
		e.preventDefault(); // disable default scrolling

		var delta = normalizeWheelDelta(e)

		pos += -delta * speed
		pos = Math.max(0, Math.min(pos, target.scrollHeight - frame.clientHeight)) // limit scrolling

		if (!moving) update()
	

	function normalizeWheelDelta(e)
		if(e.detail)
			if(e.wheelDelta)
				return e.wheelDelta/e.detail/40 * (e.detail>0 ? 1 : -1) // Opera
			else
				return -e.detail/3 // Firefox
		else
			return e.wheelDelta/120 // IE,Safari,Chrome
	

	function update() 
		moving = true
    
		var delta = (pos - target.scrollTop) / smooth
    
		target.scrollTop += delta
    
		if (Math.abs(delta) > 0.5)
			requestFrame(update)
		else
			moving = false
	

	var requestFrame = function()  // requestAnimationFrame cross browser
		return (
			window.requestAnimationFrame ||
			window.webkitRequestAnimationFrame ||
			window.mozRequestAnimationFrame ||
			window.oRequestAnimationFrame ||
			window.msRequestAnimationFrame ||
			function(func) 
				window.setTimeout(func, 1000 / 50);
			
		);
	()
p
  font-size: 16pt;
  margin-bottom: 30%;
<body onload="init()">
  <h1>Lorem Ipsum</h1>
  
  <p>Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.</p>
  
  <p>Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.</p>
  
  <p>Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.</p>
</body>

拨打new SmoothScroll(target,speed,smooth)使用它

参数:

    target:要平滑滚动的元素——可以是div或者document 速度:每个鼠标滚轮滚动的像素数量 步骤 smooth:平滑系数,数值越高越 流畅。

感谢@Phrogz 提供mousewheel normalization。

编辑:从 Chrome 73 开始,需要将 mousewheel 事件的事件侦听器标记为非被动,以便能够在其上调用 preventDefault()。感谢@Fred K。

【讨论】:

这似乎是迄今为止最好的实现,又好又流畅。感谢您抽出宝贵时间调查此问题。干杯:) 这个解决方案很漂亮! 您好,我非常喜欢您的解决方案,并在 NuxtJS 项目中使用了它。我做了一些修改,并认为我会分享它们;允许作为 ECMAScript 2015 模块加载,不会在滚动条上触发(由于某种原因 DOMMouseScroll 导致此问题),修复了浏览器偏移量阻止您一直滚动到顶部/底部的问题:gist.github.com/SamJakob/c9175a4c2440e1b14b0b8cf7d99d2d24 @JordanBelf 我也有兴趣。我有一个问题,当您第一次使用鼠标然后使用滚动条或其他东西时,滚动会跳动。 @TheTrueTDF 这是我最终使用的代码,我不记得确切,也找不到时间再次分析它,但我记得它涉及用新的更新 pos 变量pos 一旦用户点击一个链接。希望代码对jsfiddle.net/tw0xc1L2有帮助【参考方案2】:

您发布的代码几乎是 vanilla js。只是一些调整

如果你有时间看看The wheel event

这里的新功能是动画功能

// Code goes here

document.addEventListener('wheel',function (event)
  //only vertical scroll
  if (event.deltaY > 0)
  
    event.preventDefault();
    smoothScroll(document.documentElement,100,1000)
  
)
function smoothScroll (domElement,pixel,delay)

  const intervalToRepeat = 25;
  const step = (intervalToRepeat * pixel) / delay;
  if ( step < pixel)
  
    domElement.scrollTop += step;
    setTimeout(function ()
      smoothScroll(domElement,pixel - step,delay)
    ,intervalToRepeat);
  
  
  

  
<!DOCTYPE html>
<html>

  <head>
    <link rel="stylesheet" href="style.css">
    <script src="script.js"></script>
  </head>

  <body>
    <h1>Hello Plunker!</h1>
    
    <div style="width:400px;height:200px;" >
      lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some 
      lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some 
      lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some 
      lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some 
      <br>
      lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some 
      lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some 
      lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some 
      lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some 
      lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some 
      lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some 
      lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some 
      lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some 
      lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some 
      <br>
      lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some 
      lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some 
      lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some 
      lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some 
      lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some <br>
      lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some 
      lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some 
      lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some 
      lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some 
      lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some <br>
      lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some 
      lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some 
      lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some 
      lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some 
      lorem ipsum some lorem ipsum some lorem ipsum some lorem ipsum some 
      
    </div>
  </body>

</html>

【讨论】:

很好,但是如果已经向下滚动,向上滚动会有问题。此外,繁忙的页面会导致滚动问题。而不是根据距离设置延迟。选择一个小的延迟,比如 5ms,然后每次你的函数运行时检查自上次运行以来的时间戳,并将滚动位置更新为计划滚动时间和滚动距离的一部分,而不仅仅是距离。【参考方案3】:

纯 JavaScript onscroll 事件将起作用:

var container = document.getElementById('myScrollingSurface');
var lastY = 0;
container.onscroll = function () 
  doSomethingCool(container.scrollTop - lastY);
  lastY = container.scrollTop;
;

【讨论】:

以上是关于香草javascript中鼠标滚轮上的平滑垂直滚动?的主要内容,如果未能解决你的问题,请参考以下文章

Javascript - 使用鼠标滚轮平滑视差滚动

使用鼠标滚轮平滑滚动 QTableWidget

如何将鼠标滚轮滚动添加到垂直滚动条或滚动区域?

JavaScript 中的鼠标滚轮倾斜与滚动,scrollTop

带有鼠标滚轮效果的jQuery平滑滚动

使用鼠标滚轮平滑滚动缓动效果[关闭]