简体   繁体   English

为什么在mousemove上设置scrollLeft和scrollTop会导致最大滚动*意外地过早?

[英]Why setting scrollLeft and scrollTop on mousemove results in max scroll* unexpectedly early?

In answering another question on StackOverflow , I posted what was supposed to be a simple demo showing how to achieve movement of a child <div> relative to the movement of the cursor within its parent <div> , by the manipulation of element.scrollTop and element.scrollLeft . 在回答有关StackOverflow的另一个问题时 ,我发布了一个简单的演示,该演示演示了如何通过element.scrollTop和的操作实现子<div>相对于其父<div>内光标的运动element.scrollTop element.scrollLeft

My demo basically works as expected, demonstrating the basics of gathering the cursor coordinates on mousemove via event.pageX and event.pageY , doing a little math to calculate the ratio by which the larger .inner child should be moved, and applying the scroll* . 我的演示基本上按预期工作,演示了通过event.pageXevent.pageYmousemove上收集光标坐标的基本知识,做了一些数学运算以计算应移动较大的.inner子对象的比例,并应用scroll*

However , I noticed that when moving my cursor near to the bottom and/or right of the .outer parent, the .inner child would be scrolled to its maximum ahead of my cursor reaching the edge(s). 但是 ,我注意到,将光标移到.outer父级的底部和/或右侧附近时, .inner子级将在光标到达边缘之前滚动到其最大值。

What have I done to find a solution? 我做了什么来找到解决方案?
Realising that event.pageX would always be at least 1 and never more than 1 less than the width and that event.pageY would never be more than 1 less of the parent <div> 's height , I added a rudimentary function to expand the coordinate range from 0 to the full width and/or height . 意识到event.pageX将始终是至少1且绝不超过1比小于widthevent.pageY绝不会超过1少的母体<div>height ,我添加了一个基本的功能扩展坐标范围从0到全width和/或全height
Although the function does its job, it didn't cure the premature maximum scroll* . 尽管该功能可以发挥作用,但并不能解决最大过早scroll*

EDIT : I had not tested this code outside SO snippets which appear to present the HTML differently depending on if it's being edited, viewed normally or expanded; 编辑 :我没有在SO片段之外测试过此代码,这些片段根据是被编辑,正常查看还是扩展显示了不同的HTML形式。 Sometimes the function is required , and sometimes it's presence results in negative values. 有时该功能是必需的 ,有时它的存在会导致负值。

scrollTop doesn't respond to negative values; scrollTop不响应负值; instead, it sets itself back to 0 . 相反,它将自身设置回0

If set to a value greater than the maximum available for the element, scrollTop settles itself to the maximum value. 如果设置的值大于该元素的最大可用值,则scrollTop会将其自身设置为最大值。

The same is true for scrollLeft . scrollLeft也是如此。
So this inconsistency isn't relevant; 因此,这种不一致是不相关的。 the problem was evident before I added the function. 在添加功能之前,问题很明显。

What else? 还有什么?
I have repeatedly checked the math and, eg 我已经反复检查过数学, 例如

  • Say we have a parent <div> measuring 100px by 100px 假设我们有一个父<div>尺寸为100px x 100px
  • And a child <div> measuring 300px by 300px ( 3 times the parent on both axes) 还有一个子300px <div>尺寸为300px x 300px (两个轴上父300px 3倍)
  • If the cursor is at coord. 如果光标在坐标上。 { x: 90, y: 90 }
  • The scrollTop should be set to 90 * 3 = 270 scrollTop应该设置为90 * 3 = 270
  • And scrollLeft should be set to 90 * 3 = 270 并且scrollLeft应该设置为90 * 3 = 270
  • So the child <div> 's bottom or right edges should not be aligned with those of the parent. 所以,孩子<div>的底部或右侧边缘应该与家长的一致。

With that in mind, as I say, I have checked and checked again, and the math should work, but the result is unexpected. 考虑到这一点,正如我所说的,我已经检查了一次,然后数学运算就可以了 ,但结果出乎意料。

Here's the code , with some extra bits outputting some of the the numbers in innerHTML (the console gets in the way a bit otherwise), and my question will continue under it. 这是代码 ,其中一些额外的位输出了innerHTML一些数字(控制台以其他方式妨碍了它),我的问题将在其下继续。 The extra <output> UI doesn't affect the result. 额外的<output> UI不会影响结果。

 const divs = document.querySelectorAll( "div" ), outer_div = divs[ 0 ], outer_div_styles = window.getComputedStyle( outer_div ), inner_div_styles = window.getComputedStyle( divs[ 1 ] ), outer_div_width = parseInt( outer_div_styles.width ), outer_div_height = parseInt( outer_div_styles.height ), dimention_ratio = { x: parseInt( inner_div_styles.width ) / outer_div_width, y: parseInt( inner_div_styles.height ) / outer_div_height }, half_odw = outer_div_width / 2, half_odh = outer_div_height / 2, expandCoords = function( e ) { // sometimes useful, never harmful var X = e.pageX, Y = e.pageY; if ( X < half_odw ) { X -= 1; } else if ( X > half_odw ) { X += 1; } if ( Y < half_odh ) { Y -= 1; } else if ( Y > half_odh ) { Y += 1; } return { x: X, y: Y }; }, // for demo convenience output = document.querySelector( "output" ); outer_div.addEventListener( "mousemove", function( evt ) { evt = expandCoords( evt ); // for demo convenience output.innerHTML = "Coords: x:" + evt.x + ", y:" + evt.y + "<br>" + "scrollLeft = " + ( evt.x * dimention_ratio.x ) + "<br>" + "scrollTop = " + ( evt.y * dimention_ratio.y ); outer_div.scrollLeft = evt.x * dimention_ratio.x; outer_div.scrollTop = evt.y * dimention_ratio.y; }, false ); 
 body { overflow: hidden; margin: 0; } .outer { width: 100vw; height: 100vh; overflow: hidden; } .inner { width: 1000vw; /* 10 times the width of its parent */ height: 500vh; /* 5 times the height of its parent */ box-shadow: inset 0 0 20px 20px green; /* no border edge highlight */ background: radial-gradient( white, black ); } /* for demo convenience */ output { position: absolute; top: 10vh; left: 10vw; font-family: Consolas, monospace; background: white; padding: .2em .4em .3em; cursor: default; } 
 <div class="outer"><div class="inner"></div><output></output></div> 

As you should see, the right and bottom edge(s) of the child <div> come into view long before the cursor reaches the right and/or bottom edge(s) of the parent. 如您所见,子<div>的右边缘和底边缘早在光标到达父对象的右边缘和/或底边缘之前<div>可见。

Why is this, and how can it be fixed in a dynamic application? 为什么会这样,如何在动态应用程序中修复它?

By "dynamic application" I mean without hard coding the solution on a case by case basis. “动态应用”是指无需根据具体情况对解决方案进行硬编码。

NOTE : Although (I know) this code can be optimized in many ways, it is purely for demonstration and thus, optimisations that do not affect a fix for the specific problem are not of interest. 注意 :尽管(我知道)此代码可以通过多种方式进行优化 ,但它仅用于演示,因此,不影响不解决特定问题的优化的优化就没有意义了。

I figured it out 我想到了

scrollTop and scrollLeft are the measure of how many pixels are scrolled on their respective axes. scrollTopscrollLeft是在其各自的轴上滚动多少像素的度量。
This equates to how much is scrolled out of view , so there is always an amount remaining that cannot be scrolled. 这等于从视线中滚动多少,因此始终有无法滚动的剩余量。
This amount is equal to the respective measure of the parent. 此金额等于父项的相应度量。

  • If the child <div> is twice the size of the parent, then when scrolled to its maximum on either axes, only half will be scrolled. 如果子<div>的大小是父元素大小的两倍,则在任一轴上滚动到其最大值时,将只滚动一半。
  • If the child is three times the size, at max scroll, two thirds will be scrolled. 如果孩子的尺寸是孩子的三倍,则最大滚动时,将滚动三分之二。
  • 10 times the size: 9/10ths scrolled etc. 大小的10倍:滚动9/10ths 等等

In this particular application, the cursor coordinates should be multiplied by the dimension ratios calculated as: 在此特定应用中,光标坐标应乘以如下计算的尺寸比例:

( width of the child minus the width of the parent ) divided by the width of the parent
and
( height of the child minus the height of the parent ) divided by the height of the parent

So the corrected code, handling arbitrary ratios: 因此,更正后的代码可以处理任意比率:

 const divs = document.querySelectorAll( "div" ), outer_div = divs[ 0 ], outer_div_styles = window.getComputedStyle( outer_div ), inner_div_styles = window.getComputedStyle( divs[ 1 ] ), outer_div_width = parseInt( outer_div_styles.width ), outer_div_height = parseInt( outer_div_styles.height ), dimention_ratio = { x: ( parseInt( inner_div_styles.width ) - outer_div_width ) / outer_div_width, // fixed y: ( parseInt( inner_div_styles.height ) - outer_div_height ) / outer_div_height // fixed }, half_odw = outer_div_width / 2, half_odh = outer_div_height / 2, expandCoords = function( e ) { var X = e.pageX, Y = e.pageY; if ( X < half_odw ) { X -= 1; } else if ( X > half_odw ) { X += 1; } if ( Y < half_odh ) { Y -= 1; } else if ( Y > half_odh ) { Y += 1; } return { x: X, y: Y }; }; outer_div.addEventListener( "mousemove", function( evt ) { evt = expandCoords( evt ); outer_div.scrollLeft = evt.x * dimention_ratio.x; outer_div.scrollTop = evt.y * dimention_ratio.y; }, false ); 
 body { overflow: hidden; margin: 0; } .outer { width: 100vw; height: 100vh; overflow: hidden; } .inner { width: 1234vw; /* 12.34 times the width of its parent */ height: 567vh; /* 5.67 times the height of its parent */ box-shadow: inset 0 0 20px 20px green; /* no border edge highlight */ background: radial-gradient( white, black ); } 
 <div class="outer"><div class="inner"></div></div> 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 在mousemove上对scrollLeft和scrollTop进行动画处理 - Animate scrollLeft & scrollTop on mousemove 为什么有时scrollTop / scrollLeft不可写? - Why sometime scrollTop/scrollLeft not writable? 消除在其他元素的滚动事件上更新元素的scrolltop / scrollleft的延迟 - remove delay in updating scrolltop/ scrollleft of an element on scroll event of other element 进行“ scrollLeft” /“ scrollTop”更改不会触发滚动事件监听器 - Make “scrollLeft” / “scrollTop” changes not trigger scroll event listener 水平网站上的scrollTop或scrollLeft? - scrollTop or scrollLeft on horizontal website? 同时设置 scrollLeft 和 scrollTop - Set scrollLeft and scrollTop simultaneously 使用-webkit-overflow-scrolling:touch时的当前滚动位置:Safari iOS javascript事件(scrollTop / scrollLeft) - Current scroll position when using -webkit-overflow-scrolling:touch - Safari iOS javascript event (scrollTop / scrollLeft) jquery scrolltop和scrollleft完美地工作,但在iPhone上他们都滚动另一个酒吧到它的原位? - jquery scrolltop and scrollleft work perfectly, but on iphone they all scroll the other bar to it's home position? 使用负的scrollTop / scrollLeft值进行动画处理 - Animate with a negative scrollTop/scrollLeft value jQuery - 如何检测scrollLeft和scrollTop - jQuery - How to detect scrollLeft AND scrollTop
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM