[英]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.pageX
和event.pageY
在mousemove
上收集光标坐标的基本知识,做了一些数学运算以计算应移动较大的.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
比小于width
和event.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 to0
.相反,它将自身设置回
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 我已经反复检查过数学, 例如
<div>
measuring 100px
by 100px
<div>
尺寸为100px
x 100px
<div>
measuring 300px
by 300px
( 3 times the parent on both axes) 300px
<div>
尺寸为300px
x 300px
(两个轴上父300px
3倍) { x: 90, y: 90 }
scrollTop
should be set to 90 * 3
= 270
scrollTop
应该设置为90 * 3
= 270
scrollLeft
should be set to 90 * 3
= 270
scrollLeft
应该设置为90 * 3
= 270
<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. 注意 :尽管(我知道)此代码可以通过多种方式进行优化 ,但它仅用于演示,因此,不影响不解决特定问题的优化的优化就没有意义了。
scrollTop
and scrollLeft
are the measure of how many pixels are scrolled on their respective axes. scrollTop
和scrollLeft
是在其各自的轴上滚动多少像素的度量。
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. 此金额等于父项的相应度量。
<div>
is twice the size of the parent, then when scrolled to its maximum on either axes, only half will be scrolled. <div>
的大小是父元素大小的两倍,则在任一轴上滚动到其最大值时,将只滚动一半。 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
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.