JavaScript:在 Chrome 中使用 textarea.setSelectionRange 后滚动到选择

Posted

技术标签:

【中文标题】JavaScript:在 Chrome 中使用 textarea.setSelectionRange 后滚动到选择【英文标题】:JavaScript: Scroll to selection after using textarea.setSelectionRange in Chrome 【发布时间】:2011-11-19 19:50:46 【问题描述】:

javascript 函数使用 .setSelectionRange() 选择文本区域中的某个单词。在 Firefox 中,文本区域会自动向下滚动以显示选定的文本。在 Chrome (v14) 中,它没有。有没有办法让 Chrome 将文本区域向下滚动到新选择的文本?欢迎使用 jQuery 解决方案。

【问题讨论】:

【参考方案1】:

这里有一个简单高效的解决方案,纯js:

//first of all, you ignore any bad english, as i'm french and had a funny evening
//get the textarea
var textArea = document.getElementById('myTextArea');

//define your selection
var selectionStart = 50;
var selectionEnd = 60;
textArea.setSelectionRange( selectionStart, selectionEnd);

// now lets do some math
// we need the number of chars in a row
var charsPerRow = textArea.cols;

// we need to know at which row our selection starts
var selectionRow = (selectionStart - (selectionStart % charsPerRow)) / charsPerRow;

// we need to scroll to this row but scrolls are in pixels,
// so we need to know a row's height, in pixels
var lineHeight = textArea.clientHeight / textArea.rows;

// scroll !!
textArea.scrollTop = lineHeight * selectionRow;

把这个放在一个函数中,用它扩展javascript的Element对象的原型,就可以了。

如果您需要任何进一步的帮助,请随时询问。

【讨论】:

charsPerRow 逻辑忽略换行符,软(单词之间换行)和硬(实际换行)。 你完全正确!我目前正在检查您的解决方案【参考方案2】:

很多答案,但是accepted one 没有考虑换行,Matthew Flaschen 没有添加解决方案代码,naXa 答案有错误。最简单的解决方案代码是:

textArea.focus();

const fullText = textArea.value;
textArea.value = fullText.substring(0, selectionEnd);
textArea.scrollTop = textArea.scrollHeight;
textArea.value = fullText;

textArea.setSelectionRange(selectionStart, selectionEnd);

【讨论】:

所有聪明的操作都发生在一个“集中”的texarea上是非常重要的。 textArea.focus() 应该在顶部【参考方案3】:

您可以看到我们如何解决问题in ProveIt(请参阅 highlightLengthAtIndex)。基本上,诀窍是截断文本区域,滚动到末尾,然后恢复文本的第二部分。我们还使用 textSelection 插件来实现一致的跨浏览器行为。

【讨论】:

嗨,马特,只是建议,将代码放入您的答案中,以便我们可以在 SO 而不是链接中看到它们。 对您的代码添加一些 cmets,以防您还没有遇到它。而不是 document.getElementById("my_textarea") ,你可以做 jQuery('#my_textarea').get(0)【参考方案4】:

这是受 Matthew Flaschen 的 answer 启发的代码。

/**
 * Scroll textarea to position.
 *
 * @param htmlInputElement textarea
 * @param Number position
 */
function scrollTo(textarea, position) 
    if (!textarea)  return; 
    if (position < 0)  return; 

    var body = textarea.value;
    if (body) 
        textarea.value = body.substring(0, position);
        textarea.scrollTop = position;
        textarea.value = body;
    

基本上,诀窍是截断文本区域,滚动到末尾,然后恢复文本的第二部分。

如下使用

var textarea, start, end;
/* ... */

scrollTo(textarea, end);
textarea.focus();
textarea.setSelectionRange(start, end);

【讨论】:

变量position 既用作子字符串索引,又用作采用像素的scrollTop 是没有意义的。【参考方案5】:

Valeriy Katkov 的 elegant solution 效果很好,但有两个问题:

    不适用于长字符串 所选内容会滚动到文本区域的底部,因此很难看到围绕所选内容的上下文

这是我的改进版本,适用于长字符串(测试至少 50,000 个单词)并将选择滚动到文本区域的中心:

function setSelectionRange(textarea, selectionStart, selectionEnd) 
    // First scroll selection region to view
    const fullText = textarea.value;
    textarea.value = fullText.substring(0, selectionEnd);
    // For some unknown reason, you must store the scollHeight to a variable
    // before setting the textarea value. Otherwise it won't work for long strings
    const scrollHeight = textarea.scrollHeight
    textarea.value = fullText;
    let scrollTop = scrollHeight;
    const textareaHeight = textarea.clientHeight;
    if (scrollTop > textareaHeight)
        // scroll selection to center of textarea
        scrollTop -= textareaHeight / 2;
     else
        scrollTop = 0;
    
    textarea.scrollTop = scrollTop;

    // Continue to set selection range
    textarea.setSelectionRange(selectionStart, selectionEnd);

适用于 Chrome 72、Firefox 65、Opera 58 和 Edge 42

有关使用此功能的示例,请参阅我的 GitHub 项目SmartTextarea。

【讨论】:

【参考方案6】:

基于@naXa 和@Valeriy Katkov 的想法,我改进了功能,减少了错误。它应该开箱即用(它是用 TypeScript 编写的。对于 JavasCript,只需删除类型声明):

function scrollTo(textarea: HTMLTextAreaElement, offset: number) 
    const txt = textarea.value;
    if (offset >= txt.length || offset < 0)
      return;
    textarea.scrollTop = 0;  // Important, so that scrollHeight will be adjusted
    textarea.value = txt.substring(0, offset);
    const height = textarea.scrollHeight;
    textarea.value = txt;
    textarea.scrollTop = height - 40;  // Margin between selection and top of viewport

用法:

let textarea, start, end;
/* ... */

scrollTo(textarea, start);
textarea.focus();
textarea.setSelectionRange(start, end);

【讨论】:

【参考方案7】:

Chrome 的完整代码

<script type="text/javascript">
            var SAR = ;

            SAR.find = function () 
                debugger;
                var parola_cercata = $("#text_box_1").val(); // the searched word
                // make text lowercase if search is supposed to be case insensitive
                var txt = $('#remarks').val().toLowerCase();
                parola_cercata = parola_cercata.toLowerCase();

                var posi = jQuery('#remarks').getCursorPosEnd(); // take the position of the word in the text

                var termPos = txt.indexOf(parola_cercata, posi);

                if (termPos !== -1) 
                    debugger;
                    var target = document.getElementById("remarks");
                    var parola_cercata2 = $("#text_box_1").val();
                    // select the textarea and the word
                    if (target.setSelectionRange) 

                        if ('selectionStart' in target) 
                            target.selectionStart = termPos;
                            target.selectionEnd = termPos;
                            this.selectionStart = this.selectionEnd = target.value.indexOf(parola_cercata2);
                            target.blur();
                            target.focus();
                            target.setSelectionRange(termPos, termPos + parola_cercata.length);
                        
                     else 
                        var r = target.createTextRange();
                        r.collapse(true);
                        r.moveEnd('character', termPos + parola_cercata);
                        r.moveStart('character', termPos);
                        r.select();
                    
                 else 
                    // not found from cursor pos, so start from beginning
                    termPos = txt.indexOf(parola_cercata);
                    if (termPos !== -1) 
                        var target = document.getElementById("remarks");
                        var parola_cercata2 = $("#text_box_1").val();
                        // select the textarea and the word
                        if (target.setSelectionRange) 

                            if ('selectionStart' in target) 
                                target.selectionStart = termPos;
                                target.selectionEnd = termPos;
                                this.selectionStart = this.selectionEnd = target.value.indexOf(parola_cercata2);
                                target.blur();
                                target.focus();
                                target.setSelectionRange(termPos, termPos + parola_cercata.length);
                            
                         else 
                            var r = target.createTextRange();
                            r.collapse(true);
                            r.moveEnd('character', termPos + parola_cercata);
                            r.moveStart('character', termPos);
                            r.select();
                        
                     else 
                        alert("not found");
                    
                
            ;


            $.fn.getCursorPosEnd = function () 
                var pos = 0;
                var input = this.get(0);
                // IE Support
                if (document.selection) 
                    input.focus();
                    var sel = document.selection.createRange();
                    pos = sel.text.length;
                
                // Firefox support
                else if (input.selectionStart || input.selectionStart === '0')
                    pos = input.selectionEnd;
                return pos;
            ;
</script> 

【讨论】:

对我来说非常有效,请检查并恢复已解决的问题,以便在 textarea 上滚动以进行单词搜索【参考方案8】:

我在这里发表了一个答案:

http://blog.blupixelit.eu/scroll-textarea-to-selected-word-using-javascript-jquery/

它与 jsut 一个需要的规则完美配合:在 textarea 的 css 中设置一个 line-height!

它仅通过一些简单的数学计算来计算要滚动到的单词的位置,并且在我的所有实验中都能完美运行!

如果您对代码有任何需要,请随时问我!

【讨论】:

虽然此链接可能会回答问题,但最好在此处包含答案的基本部分并提供链接以供参考。如果链接页面发生更改,仅链接的答案可能会失效。

以上是关于JavaScript:在 Chrome 中使用 textarea.setSelectionRange 后滚动到选择的主要内容,如果未能解决你的问题,请参考以下文章

new Date() 在 Chrome 和 Firefox 中的工作方式不同

jQuery 函数在 Chrome 中不起作用

在 Javascript 中使用 appendChild 和 IE

使用JavaScript / JQuery导出 html table 数据至 Excel 兼容IE/Chrome/Firefox

使用Javascript在chrome中禁用保存密码气泡[重复]

如何在 Chrome 扩展中使用 Javascript 获取文件大小?