简体   繁体   English

如何使用插入符号 position 在文本区域中垂直导航

[英]How to vertically navigate through a textarea using caret position

I'm working on a set of vanilla js functions to navigate an html textarea when the appropriate arrow button is clicked.我正在研究一组 vanilla js 函数,以在单击相应的箭头按钮时导航 html 文本区域。

for example,例如,

 var text = document.getElementById('text'); function larr(){ text.focus(); var pos = text.selectionStart; pos-- text.setSelectionRange(pos, pos); }
 <textarea id='text'></textarea> <button onclick="larr()">&larr;</button>

The left and right functions are simple enough, but I would also like to include up and down arrows.左右功能很简单,但我还想包括向上和向下箭头。 Since each newline can have a different amount of characters, I don't think it is as simple as setting the position forward or back one max-line-length.由于每个换行符可以有不同数量的字符,我认为这不像将 position 向前或向后设置一个最大行长度那么简单。

I would settle for the arrows taking you to the next or previous line break.我会满足于将您带到下一个或上一个换行符的箭头。 I was thinking about splitting the textarea value at the caret position and looping through characters in that direction until a \n is reached, but I can't wrap my head around it.我正在考虑在插入符号 position 处拆分 textarea 值,并在该方向上循环字符直到达到 \n,但我无法绕开它。

Does anyone have any suggestions?有没有人有什么建议? Thanks!谢谢!

* IMPORTANT NOTE - this would be for mobile with the native keyboard hidden , so no help from the os? *重要提示-这将适用于隐藏本机键盘的移动设备,因此没有操作系统的帮助? (unless maybe jquery trigger() or execCommand?) (除非可能是 jquery trigger() 或 execCommand?)

Caveat: it is recommended if you use this method to disable the ability to resize your textarea.警告:如果您使用此方法禁用调整文本区域大小的功能,建议您使用。 This way you can control the adjustor needed to account for the difference of varying sizes of charactrer widths and how selection of characters varies in terms of actual width with textarea wordwrap.通过这种方式,您可以控制所需的调整器,以考虑不同大小的字符宽度的差异以及使用 textarea 自动换行根据实际宽度选择字符的方式。

NOTE: Did not test this on MOBILE VERSION.注意:没有在移动版上进行测试。

I was able to get this to work using a couple of functions I found online here: How to get number of rows in textarea using JavaScript?我可以使用我在这里在线找到的几个函数来实现它:如何使用 JavaScript 获取textarea中的行数? . . Basically the poster used the height, line-height, overflow and scroll-height to determine the height of the textarea and, in short, get the amount of lines within the textareas content.基本上,海报使用高度、行高、溢出和滚动高度来确定 textarea 的高度,简而言之,获取 textareas 内容中的行数。 I included the posters original comments to help you understand the logic.我包括了海报的原始评论,以帮助您理解逻辑。 I adjusted their second function to divide the amount of lines with the amount of characters within the textarea, this gives us a rudimentary idea of how wide each line is, although it is not precise!我调整了他们的第二个 function 以将行数除以文本区域内的字符数,这使我们对每行的宽度有一个基本的了解,尽管它并不精确! See Caveat... Depending on the characters within each line, which can change depending on the width of the textarea, the rounded amount of characters in the line will vary.请参阅警告...根据每行中的字符(可能会根据 textarea 的宽度而变化),行中字符的四舍五入量会有所不同。 So when we go up a line or down a line it will jump right or left depending on that variation.因此,当我们 go 向上或向下一行时,它会根据该变化向右或向左跳跃。

How we get the line up/down...我们如何上/下线...

    let style = (window.getComputedStyle) ?
    window.getComputedStyle(text) : text.currentStyle,

    // This will get the line-height if it is set in the css
    textLineHeight = parseInt(style.lineHeight, 10),
    // Get the scroll height of the textarea
    textHeight = calculateContentHeight(text, textLineHeight),
    // calculate the number of lines by dividing
    // the scroll height by the line-height
    numberOfLines = Math.ceil(textHeight / textLineHeight),
    // get the amount of characters in the textarea
    numOfChars = text.value.length,
    // this following number will vary depending on how the width of your 
    // lines character count is calculated and rounded in terms 
    // of what the actual width in character count actually is
    // you will have to adjust this number accordingly
    adjustor = 14,
    // divide the number of characters by the amount of lines
    percentage = numOfChars / numberOfLines + adjustor;

    return percentage;

Again, this is not as precise with the up and down but it works, moving the cursor up or down on button press it shifts lightly left or right depending on the amount the rounded count of characters is against the amount on that particular line.同样,这在向上和向下时并不精确,但它可以工作,在按下按钮时向上或向下移动 cursor,它会根据字符的四舍五入数量与该特定行上的数量进行轻微的左右移动。

EDIT: I have combined your movement functions into one function that runs the button class through a forEach loop and uses the event target to check the ID of each element and move the cursor accordingly.编辑:我已将您的移动功能组合到一个 function 中,该功能通过forEach循环运行按钮class 并使用事件目标检查每个元素的ID并相应地移动 Z1791A97A8403730EE0760489A2AEB9Z。

 let text = document.getElementById('text'); text.value = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Mauris in aliquam sem fringilla ut morbi tincidunt augue. Scelerisque in dictum non consectetur a erat nam. Consectetur adipiscing elit ut aliquam purus sit amet luctus venenatis. "; // lets just set a cursor middle of the road for testing... text.focus(); text.setSelectionRange(181, 181); let calculateContentHeight = (text, scanAmount) => { let origHeight = text.style.height, height = text.offsetHeight, scrollHeight = text.scrollHeight, overflow = text.style.overflow; /// only bother if the ta is bigger than content if (height >= scrollHeight) { /// check that our browser supports changing dimension /// calculations mid-way through a function call... text.style.height = `${(height + scanAmount)}px`; /// because the scrollbar can cause calculation problems text.style.overflow = 'hidden'; /// by checking that scrollHeight has updated if (scrollHeight < text.scrollHeight) { /// now try and scan the ta's height downwards /// until scrollHeight becomes larger than height while (text.offsetHeight >= text.scrollHeight) { text.style.height = `${(height -= scanAmount)}px`; } /// be more specific to get the exact height while (text.offsetHeight < text.scrollHeight) { text.style.height = `${(height++)}px`; } /// reset the ta back to it's original height text.style.height = origHeight; /// put the overflow back text.style.overflow = overflow; return height; } } else { return scrollHeight; } } let calculateLineWidth = (text) => { let style = (window.getComputedStyle)? window.getComputedStyle(text): text.currentStyle, // This will get the line-height only if it is set in the css, // otherwise it's "normal" textLineHeight = parseInt(style.lineHeight, 10), // Get the scroll height of the textarea textHeight = calculateContentHeight(text, textLineHeight), // calculate the number of lines numberOfLines = Math.ceil(textHeight / textLineHeight), // get the amount of characters in the textarea numOfChars = text.value.length, // this number will vary depending on how the width of your // lines character count is calculated and rounded in terms // of what the actual width in character count actually is // you will have to adjust this number accordingly adjustor = 14, // divide the number of characters by the amount of lines percentage = numOfChars / numberOfLines + adjustor; return percentage; } const moveCursor = (text) => { const btns = document.querySelectorAll('.btns'); btns.forEach((btn) => { btn.addEventListener('click', (e) => { text.focus(); let pos = text.selectionStart; if (e.target.id === 'left') { pos--; text.setSelectionRange(pos, pos); } else if (e.target.id === 'right') { pos++; text.setSelectionRange(pos, pos); } else if (e.target.id === 'up') { if (pos - Number(calculateLineWidth(text)) > 0) { pos = pos - Number(calculateLineWidth(text)); text.setSelectionRange(pos, pos); } else { text.setSelectionRange(0, 0); } } else { pos = pos + Number(calculateLineWidth(text)); text.setSelectionRange(pos, pos) } }) }) } moveCursor(text);
 #text { line-height: 1.5; text-align: justify; resize: none; } #btns { display: flex; align-items: center; } #mid { display: flex; flex-direction: column; }.btns { height: 20px; }
 <textarea id='text' cols="50" rows="6"></textarea> <div id="btns"> <button id="left" class="btns">&larr;</button> <div id="mid"> <button id="up" class="btns">&#129045;</button> <button id="down" class="btns">&#129043;</button> </div> <button id="right" class="btns">&rarr;</button> </div>

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM