Why setting scrollLeft and scrollTop on mousemove results in max scroll* unexpectedly early?
在回答有关StackOverflow的另一个问题时,我发布了一个简单的演示,该演示演示如何通过操纵
我的演示基本上按预期工作,演示了通过
但是,我注意到当将光标移到
我为寻找解决方案做了什么?
意识到
尽管该功能可以发挥作用,但不能解决最大过早的
编辑:我没有在SO片段之外测试过此代码,这些片段根据是被编辑,正常查看还是展开而似乎呈现不同的HTML。有时该功能是必需的,有时它的存在会导致负值。
scrollTop doesn't respond to negative values; instead, it sets itself back to0 .If set to a value greater than the maximum available for the element,
scrollTop settles itself to the maximum value.
因此,这种不一致是无关紧要的。在添加功能之前,问题很明显。
还有什么?
我已经反复检查过数学,例如
-
假设我们有一个父
用 100px 来度量100px -
还有一个子项
用 300px 来度量300px (两个轴上父级的3倍) -
如果光标在坐标上。
{ x: 90, y: 90 } -
scrollTop 应设置为90 * 3 =270 -
并且
scrollLeft 应该设置为90 * 3 =270 -
因此,子级
的底部或右侧边缘不应与父级的底部或右侧边缘对齐。
考虑到这一点,正如我所说的,我已经检查了一次并再次检查了一下,数学应该可以工作,但是结果出乎意料。
这是代码,其中一些额外的位输出了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | 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 +"" + "scrollLeft =" + ( evt.x * dimention_ratio.x ) +"" + "scrollTop =" + ( evt.y * dimention_ratio.y ); outer_div.scrollLeft = evt.x * dimention_ratio.x; outer_div.scrollTop = evt.y * dimention_ratio.y; }, false ); |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | 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; } |
1 | <output></output> |
您应该看到,子
这是为什么,如何在动态应用程序中对其进行修复?
"动态应用"是指无需根据具体情况对解决方案进行硬编码。
注意:尽管(我知道)此代码可以通过许多方式进行优化,但它仅用于演示,因此,不影响不解决特定问题的优化的优化就没有意义了。
我想到了
这等于滚动了多少视线,因此始终有无法滚动的剩余量。
此数量等于父项的相应度量。
-
如果子代
的大小是父代大小的两倍,则在任一轴上滚动到其最大值时,将只滚动一半。 - 如果孩子的大小是孩子的三倍,则最大滚动时,将滚动三分之二。
-
10 乘以大小:9/10ths 滚动等
在此特定应用中,光标坐标应乘以计算出的尺寸比例:
和
因此,更正后的代码可以处理任意比率:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | 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 ); |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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 ); } |
1 |