当用户在长文本中间插入换行符时,如何防止Chrome的textarea中的光标跳到顶部?
How do I prevent the cursor in Chrome's textarea from jumping to the top when the user inserts a newline in the middle of a long text?
如果 <textarea>
有很多文本(即超过文本区域高度的两倍),当用户在中间插入一个换行符时,Chrome 滚动文本这样光标位于 <textarea>
的顶部。这种行为会让用户迷失方向,因为他们必须手动滚动文本区域才能将上方的内容带回视图。 Firefox 和 Safari 都没有这种行为。
重现步骤:
- 创建
<textarea>
- 将大量文本粘贴到其中
- 将光标置于文本中间
- 按输入
预期行为:
光标在textarea中的相对位置保持不变
实际行为:
文本滚动,使光标位于文本区域的顶部。
重申一下,这种行为不会发生在 Safari 或 Firefox 中。它特定于 Chrome.
有什么方法可以在 Chrome 中抑制这种行为并使其表现得更像 Firefox 和 Safari?
这里有一个方法:
- Detect Chrome
- Count how many line breaks 用于textarea
- 输入前,检查textarea的滚动位置
- 在
input
之后,查看换行符的数量是否增加(即用户是否输入了换行符)。如果是,则重置滚动位置。
(注意:beforeinput
事件已经被 Chrome iOS supported by Chrome, but assumed not to be supported,所以在那种情况下可以使用 scroll
事件。如果你更喜欢,您可以简单地为所有情况启用滚动事件。)
function getChromeType() {
//source:
// please note,
// that IE11 now returns undefined again for window.chrome
// and new Opera 30 outputs true for window.chrome
// but needs to check if window.opr is not undefined
// and new IE Edge outputs to true now for window.chrome
// and if not iOS Chrome check
// so use the below updated condition
var isChromium = window.chrome;
var winNav = window.navigator;
var vendorName = winNav.vendor;
var isOpera = typeof window.opr !== "undefined";
var isIEedge = winNav.userAgent.indexOf("Edge") > -1;
var isIOSChrome = winNav.userAgent.match("CriOS");
if (isIOSChrome) {
// is Google Chrome on IOS
return 1;
} else if (
isChromium !== null &&
typeof isChromium !== "undefined" &&
vendorName === "Google Inc." &&
isOpera === false &&
isIEedge === false
) {
// is Google Chrome
return 2;
} else {
// not Google Chrome
return 0;
};
};
function handleChromeTextarea(el, useScroll) {
let getNoLineBreaks = () => {
//source:
return (el.value.match(/\n/g) || []).length;
};
let getScrollPos = () => {
return el.scrollTop;
};
let onInput = (e) => {
const newNoLineBreaks = getNoLineBreaks();
if (noLineBreaks < newNoLineBreaks) {
el.scrollTop = scrollPos;
};
noLineBreaks = newNoLineBreaks;
};
let onBeforeInput = (e) => {
scrollPos = getScrollPos();
};
let noLineBreaks = getNoLineBreaks();
let scrollPos = getScrollPos();
el.addEventListener("input", onInput);
el.addEventListener("beforeinput", onBeforeInput); //Already supported by Chrome - you may wish to use this without the scroll event
if (useScroll) {
el.addEventListener("scroll", onBeforeInput);
};
};
const chromeType = getChromeType();
if (0 < chromeType) {
handleChromeTextarea(document.getElementById("textarea"), (chromeType === 1));
};
<textarea id="textarea">
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Libero justo laoreet sit amet cursus. Massa eget egestas purus viverra. Quisque id diam vel quam elementum. Amet mauris commodo quis imperdiet. Viverra aliquet eget sit amet tellus cras adipiscing enim eu. Eu non diam phasellus vestibulum lorem. Morbi leo urna molestie at elementum. Massa massa ultricies mi quis hendrerit. Augue lacus viverra vitae congue eu consequat ac felis donec. Et ligula ullamcorper malesuada proin libero nunc consequat. Tincidunt dui ut ornare lectus sit amet est placerat in. Massa tempor nec feugiat nisl. Cursus euismod quis viverra nibh.
Quam lacus suspendisse faucibus interdum posuere lorem ipsum. Ut etiam sit amet nisl purus in. Magna sit amet purus gravida quis blandit turpis cursus. Sollicitudin ac orci phasellus egestas tellus rutrum tellus pellentesque. Aliquam nulla facilisi cras fermentum odio eu. Laoreet sit amet cursus sit. Fermentum iaculis eu non diam phasellus vestibulum. Feugiat in fermentum posuere urna nec tincidunt praesent semper feugiat. Dictum fusce ut placerat orci nulla pellentesque. Eu lobortis elementum nibh tellus molestie nunc non blandit massa.
Ullamcorper malesuada proin libero nunc consequat interdum varius sit amet. Blandit massa enim nec dui nunc mattis enim ut tellus. Ac turpis egestas maecenas pharetra convallis posuere morbi leo urna. Neque gravida in fermentum et sollicitudin ac orci. Blandit volutpat maecenas volutpat blandit aliquam. Felis donec et odio pellentesque diam. In cursus turpis massa tincidunt dui ut ornare lectus. Et malesuada fames ac turpis. Amet massa vitae tortor condimentum lacinia quis vel eros. Viverra vitae congue eu consequat ac. Pretium lectus quam id leo. Malesuada fames ac turpis egestas. In est ante in nibh mauris cursus mattis molestie a. Vel pharetra vel turpis nunc eget lorem dolor sed. Donec ultrices tincidunt arcu non sodales neque sodales ut etiam. Cras adipiscing enim eu turpis egestas pretium aenean pharetra magna. Risus feugiat in ante metus dictum at. Aliquet sagittis id consectetur purus ut faucibus. Sem et tortor consequat id.
Mi sit amet mauris commodo. Senectus et netus et malesuada fames. Adipiscing commodo elit at imperdiet dui accumsan. Felis eget nunc lobortis mattis aliquam. Nunc mattis enim ut tellus elementum sagittis vitae. Vitae nunc sed velit dignissim sodales ut eu sem. Mauris nunc congue nisi vitae suscipit. Id neque aliquam vestibulum morbi blandit cursus risus at ultrices. Laoreet suspendisse interdum consectetur libero id faucibus nisl tincidunt. Sollicitudin tempor id eu nisl nunc mi ipsum faucibus vitae. In egestas erat imperdiet sed euismod nisi porta lorem mollis.
Nisl rhoncus mattis rhoncus urna neque viverra justo nec. Fames ac turpis egestas integer eget aliquet nibh. Nunc consequat interdum varius sit amet. Magna fringilla urna porttitor rhoncus dolor purus non enim. Fermentum et sollicitudin ac orci phasellus egestas tellus rutrum. Integer enim neque volutpat ac tincidunt vitae semper. Mauris vitae ultricies leo integer malesuada nunc vel risus commodo. Proin nibh nisl condimentum id venenatis a condimentum. Amet mattis vulputate enim nulla aliquet porttitor lacus luctus accumsan. Eget nunc scelerisque viverra mauris. Accumsan sit amet nulla facilisi morbi tempus. Justo eget magna fermentum iaculis eu non. Fusce id velit ut tortor pretium viverra. Quam quisque id diam vel. Ut sem viverra aliquet eget sit amet tellus. At in tellus integer feugiat scelerisque varius morbi enim nunc. Leo vel fringilla est ullamcorper eget.
</textarea>
如果 <textarea>
有很多文本(即超过文本区域高度的两倍),当用户在中间插入一个换行符时,Chrome 滚动文本这样光标位于 <textarea>
的顶部。这种行为会让用户迷失方向,因为他们必须手动滚动文本区域才能将上方的内容带回视图。 Firefox 和 Safari 都没有这种行为。
重现步骤:
- 创建
<textarea>
- 将大量文本粘贴到其中
- 将光标置于文本中间
- 按输入
预期行为: 光标在textarea中的相对位置保持不变
实际行为: 文本滚动,使光标位于文本区域的顶部。
重申一下,这种行为不会发生在 Safari 或 Firefox 中。它特定于 Chrome.
有什么方法可以在 Chrome 中抑制这种行为并使其表现得更像 Firefox 和 Safari?
这里有一个方法:
- Detect Chrome
- Count how many line breaks 用于textarea
- 输入前,检查textarea的滚动位置
- 在
input
之后,查看换行符的数量是否增加(即用户是否输入了换行符)。如果是,则重置滚动位置。
(注意:beforeinput
事件已经被 Chrome iOS supported by Chrome, but assumed not to be supported,所以在那种情况下可以使用 scroll
事件。如果你更喜欢,您可以简单地为所有情况启用滚动事件。)
function getChromeType() {
//source:
// please note,
// that IE11 now returns undefined again for window.chrome
// and new Opera 30 outputs true for window.chrome
// but needs to check if window.opr is not undefined
// and new IE Edge outputs to true now for window.chrome
// and if not iOS Chrome check
// so use the below updated condition
var isChromium = window.chrome;
var winNav = window.navigator;
var vendorName = winNav.vendor;
var isOpera = typeof window.opr !== "undefined";
var isIEedge = winNav.userAgent.indexOf("Edge") > -1;
var isIOSChrome = winNav.userAgent.match("CriOS");
if (isIOSChrome) {
// is Google Chrome on IOS
return 1;
} else if (
isChromium !== null &&
typeof isChromium !== "undefined" &&
vendorName === "Google Inc." &&
isOpera === false &&
isIEedge === false
) {
// is Google Chrome
return 2;
} else {
// not Google Chrome
return 0;
};
};
function handleChromeTextarea(el, useScroll) {
let getNoLineBreaks = () => {
//source:
return (el.value.match(/\n/g) || []).length;
};
let getScrollPos = () => {
return el.scrollTop;
};
let onInput = (e) => {
const newNoLineBreaks = getNoLineBreaks();
if (noLineBreaks < newNoLineBreaks) {
el.scrollTop = scrollPos;
};
noLineBreaks = newNoLineBreaks;
};
let onBeforeInput = (e) => {
scrollPos = getScrollPos();
};
let noLineBreaks = getNoLineBreaks();
let scrollPos = getScrollPos();
el.addEventListener("input", onInput);
el.addEventListener("beforeinput", onBeforeInput); //Already supported by Chrome - you may wish to use this without the scroll event
if (useScroll) {
el.addEventListener("scroll", onBeforeInput);
};
};
const chromeType = getChromeType();
if (0 < chromeType) {
handleChromeTextarea(document.getElementById("textarea"), (chromeType === 1));
};
<textarea id="textarea">
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Libero justo laoreet sit amet cursus. Massa eget egestas purus viverra. Quisque id diam vel quam elementum. Amet mauris commodo quis imperdiet. Viverra aliquet eget sit amet tellus cras adipiscing enim eu. Eu non diam phasellus vestibulum lorem. Morbi leo urna molestie at elementum. Massa massa ultricies mi quis hendrerit. Augue lacus viverra vitae congue eu consequat ac felis donec. Et ligula ullamcorper malesuada proin libero nunc consequat. Tincidunt dui ut ornare lectus sit amet est placerat in. Massa tempor nec feugiat nisl. Cursus euismod quis viverra nibh.
Quam lacus suspendisse faucibus interdum posuere lorem ipsum. Ut etiam sit amet nisl purus in. Magna sit amet purus gravida quis blandit turpis cursus. Sollicitudin ac orci phasellus egestas tellus rutrum tellus pellentesque. Aliquam nulla facilisi cras fermentum odio eu. Laoreet sit amet cursus sit. Fermentum iaculis eu non diam phasellus vestibulum. Feugiat in fermentum posuere urna nec tincidunt praesent semper feugiat. Dictum fusce ut placerat orci nulla pellentesque. Eu lobortis elementum nibh tellus molestie nunc non blandit massa.
Ullamcorper malesuada proin libero nunc consequat interdum varius sit amet. Blandit massa enim nec dui nunc mattis enim ut tellus. Ac turpis egestas maecenas pharetra convallis posuere morbi leo urna. Neque gravida in fermentum et sollicitudin ac orci. Blandit volutpat maecenas volutpat blandit aliquam. Felis donec et odio pellentesque diam. In cursus turpis massa tincidunt dui ut ornare lectus. Et malesuada fames ac turpis. Amet massa vitae tortor condimentum lacinia quis vel eros. Viverra vitae congue eu consequat ac. Pretium lectus quam id leo. Malesuada fames ac turpis egestas. In est ante in nibh mauris cursus mattis molestie a. Vel pharetra vel turpis nunc eget lorem dolor sed. Donec ultrices tincidunt arcu non sodales neque sodales ut etiam. Cras adipiscing enim eu turpis egestas pretium aenean pharetra magna. Risus feugiat in ante metus dictum at. Aliquet sagittis id consectetur purus ut faucibus. Sem et tortor consequat id.
Mi sit amet mauris commodo. Senectus et netus et malesuada fames. Adipiscing commodo elit at imperdiet dui accumsan. Felis eget nunc lobortis mattis aliquam. Nunc mattis enim ut tellus elementum sagittis vitae. Vitae nunc sed velit dignissim sodales ut eu sem. Mauris nunc congue nisi vitae suscipit. Id neque aliquam vestibulum morbi blandit cursus risus at ultrices. Laoreet suspendisse interdum consectetur libero id faucibus nisl tincidunt. Sollicitudin tempor id eu nisl nunc mi ipsum faucibus vitae. In egestas erat imperdiet sed euismod nisi porta lorem mollis.
Nisl rhoncus mattis rhoncus urna neque viverra justo nec. Fames ac turpis egestas integer eget aliquet nibh. Nunc consequat interdum varius sit amet. Magna fringilla urna porttitor rhoncus dolor purus non enim. Fermentum et sollicitudin ac orci phasellus egestas tellus rutrum. Integer enim neque volutpat ac tincidunt vitae semper. Mauris vitae ultricies leo integer malesuada nunc vel risus commodo. Proin nibh nisl condimentum id venenatis a condimentum. Amet mattis vulputate enim nulla aliquet porttitor lacus luctus accumsan. Eget nunc scelerisque viverra mauris. Accumsan sit amet nulla facilisi morbi tempus. Justo eget magna fermentum iaculis eu non. Fusce id velit ut tortor pretium viverra. Quam quisque id diam vel. Ut sem viverra aliquet eget sit amet tellus. At in tellus integer feugiat scelerisque varius morbi enim nunc. Leo vel fringilla est ullamcorper eget.
</textarea>