最近,我的chrome版本做的事情越来越奇怪了(ubuntu 18.04上为74.0.3729.131)。我有一个小的编辑器脚本,其中包含显示代码的文本区域。文本区域具有固定的大小和垂直滚动条。除此之外,别无他求。
通常,当我插入换行符(textarea的正常行为)时,滚动条不会移动。现在,由于某种原因,它大约80%的时间向下滚动文本区域,直到插入标记的位置在文本区域的顶部。奇怪的是,如果我删除并在同一位置输入换行符,通常不会滚动。
我不确定这是否是Chrome中的一些新问题。使用相同的编辑器,以前的版本没有这个问题。
这是一个演示问题的codepen,滚动到某行,按Enter,文本区域应向下滚动。尝试几次以查看无法预测的行为(添加代码只是为了能够添加链接,因为您看到的只是一个文本区域)。
https://codepen.io/anon/pen/rgKqMb
<textarea style="width:90%;height:300px"></textarea>
对我而言,唯一避免这种情况的解决方案是停止回车键的正常行为,并将换行符添加到文本中。任何其他想法/见解都非常欢迎。
答案 0 :(得分:0)
您可以尝试使用css和js避免在textarea上发生事件,然后强制滚动到当前位置:
css:
textarea {
overflow:auto;
resize:none;
width:90%;
height:300px;
}
js: 您需要在{em> A
中插入this question的第一个答案function preventMoving(e) {
var key = (e.keyCode ? e.keyCode : e.which);
if(key == 13) {
e.preventDefault();
// A
}
}
然后在您的HTML上
<textarea onkeyup="preventMoving(event);"></textarea>
答案 1 :(得分:0)
到2020年末,Chrome版本86仍然存在?而且,令我惊讶的是,我没有找到有关此问题的更多信息(投诉)(这是我发现的唯一一件事专门针对此问题。)我观察到,这种行为不仅发生在打字中,而且还发生在打字中。粘贴任何包含换行符的文本。我还观察到,如果在发生这种情况后执行撤消操作,则会发生另一次随机滚动,使我走到页面更远的地方,而插入符号不在附近。
我做了很长时间的实验并检查了这种行为,但没有发现任何可重复的情况,这些情况可能为如何预测何时发生提供了线索。确实看起来只是“随机”。但是,对于我正在创建的NWJS编辑器应用程序,我必须解决此问题(NWJS使用Chrome for UI。)
这似乎对我有用:
首先,让我开始简单介绍一下原理。我们将“输入”侦听器和“滚动”侦听器附加到文本区域。之所以可行,是因为从我的观察来看,在随机滚动动作发生之前,会触发“ input” [1]侦听器。
滚动侦听器记录每个滚动动作并将其保存在全局prevScrollPos
中。它还会检查全局标记scrollCorrection
。
每次将文本输入到文本区域时,“输入”侦听器都会设置scrollCorrection
标志。请记住,这是在随机滚动发生之前发生的。
因此,发生下一次滚动(可能是令人讨厌的随机动作)时,滚动侦听器将清除scrollCorrection
,然后将文本区域滚动到上一个滚动位置,即,将其滚动回到之前的滚动位置。 “随机”滚动。但是问题是无法预料的,如果没有随机滚动并且有意发生下一次滚动该怎么办?没什么大不了的。这只是意味着,如果用户手动滚动,则第一个滚动事件基本上会无效,但是之后(清除scrollCorrection
后)所有内容都会正常滚动。由于在正常滚动过程中,事件是如此迅速地吐出,因此不太可能产生明显的效果。
代码如下:
let textarea;
let prevScrollPos = 0;
let scrollCorrection = false;
function onScroll(evt) {
if (scrollCorrection) {
// Reset this right off so it doesn't get retriggered by the corrction.
scrollCorrection = false;
textarea.scrollTop = prevScrollPos;
}
prevScrollPos = textarea.scrollTop;
}
function onInput(evt) {
scrollCorrection = true;
}
window.addEventListener("load", () => {
textarea = document.getElementById("example_textarea");
textarea.addEventListener("scroll", onScroll);
textarea.addEventListener("input", onInput);
})
现在让我们对其进行扩展:
还有另一个考虑。如果键入或粘贴操作将键入或粘贴的文本(进而是尖号)的结尾放在textarea视口的视图之外怎么办?在进行正常滚动时,大多数浏览器都会滚动页面[2],因此脱字符号将保持可见。但是,既然我们已经完成了滚动操作,则需要自己实现。
在下面的伪代码中,在输入文本区域时,除了设置scrollCorrection外,我们还调用了一个函数,该函数将:
在文本区域中找到插入符号的xy位置并不是一件容易的事,并且不在此答案的范围内,但是在网上搜索可以找到很多方法。大多数涉及将文本区域内容复制到具有类似字体,字体大小,文本换行等形式的非格式元素(例如div块)中,然后在所得的包含块中使用getBoundingClientRect
等。在我的情况下,我已经为编辑器完成了大部分工作,因此这并不是很多额外的费用。但是我包含了一些伪代码,以说明如何在滚动校正机制中实现这一点。 setCaretCorrection
基本上执行上述步骤1-7。
let textarea;
let prevScrollPos = 0;
let scrollCorrection = false;
let caretCorrection = 0;
function onScroll(evt) {
if (scrollCorrection) {
// Reset this right off so it doesn't get retriggered by the correction.
scrollCorrection = false;
textarea.scrollTop = prevScrollPos + caretCorrection;
caretCorrection = 0;
}
prevScrollPos = textarea.scrollTop;
}
function onTextareaInput() {
scrollCorrection = true;
setCaretCorrection();
}
function setCaretCorrection(evt) {
let caretPos = textarea.selectionStart;
let scrollingNeeded;
let amountToScroll;
/* ... Some code to determine xy position of caret relative to
textarea viewport, if it is scrolled out of view, and if
so, how much to scroll to bring it in view. ... */
if (scrollingNeeded) {
if (scrollCorrection) {
// scrollCorrection is true meaning random scroll has not occurred yet,
// so flag the scroll listener to add additional correction. This method
// won't cause a flicker which could happen if we scrollBy() explicitly.
caretCorrection = amountToScroll;
} else {
// Random scroll has already occurred and been corrected, so we are
// forced to do the additional "out of viewport" correction explicitly.
// Note, in my situation I never saw this condition happen.
textarea.scrollBy(0, amountToScroll);
}
}
}
可以更进一步,使用实验性事件“ beforeinput” [3]对其进行一点优化,以便减少对setCaretCorrection
的不必要调用。如果从“ beforeinput”事件中检查了event.data
,则在某些情况下,它将报告要输入的数据。如果不是,则输出null
。不幸的是,当键入 换行符时,event.data
是null
。但是,如果已粘贴,则会报告换行符。因此,至少可以看到event.data是否包含一个字符串,并且如果该字符串不包含换行符,则跳过整个更正操作。 (另请参见下面的[1]。
[1]我也看不到您在“ beforeinput” [3]监听器中无法执行的任何原因,以及我们在“ input”监听器中所做的事情。在随机滚动发生之前,我们还可以设置scrollCorrection
来提供更多保险。尽管注意“ beforeinput”是实验性的。
[2]我怀疑导致此问题的此功能实现不正确。
[3] https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/beforeinput_event(根据此链接,可在Chrome和除Firefox以外的所有主要浏览器上使用。)