簡體   English   中英

JavaScript:在 Chrome 中使用 textarea.setSelectionRange 后滾動到選擇

[英]JavaScript: Scroll to selection after using textarea.setSelectionRange in Chrome

javascript 函數使用 .setSelectionRange() 在 textarea 中選擇某個單詞。 在 Firefox 中,文本區域會自動向下滾動以顯示所選文本。 在 Chrome (v14) 中,它沒有。 有沒有辦法讓 Chrome 將 textarea 向下滾動到新選擇的文本? 歡迎使用 jQuery 解決方案。

這是一個簡單有效的解決方案,純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 對象的原型,你就很好了。

如果您需要任何進一步的幫助,請隨時詢問。

很多答案,但接受的沒有考慮換行, 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);

您可以在 ProveIt 中看到我們是如何解決問題(請參閱 highlightLengthAtIndex)。 基本上,訣竅是截斷textarea,滾動到末尾,然后恢復文本的第二部分。 我們還使用了 textSelection 插件來實現一致的跨瀏覽器行為。

這是一個受 Matthew Flaschen's 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;
    }
}

基本上,訣竅是截斷textarea,滾動到末尾,然后恢復文本的第二部分。

使用方法如下

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

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

Valeriy Katkov 的優雅解決方案效果很好,但有兩個問題:

  1. 不適用於長字符串
  2. 選中的內容會滾動到 textarea 的底部,很難看到選中的上下文

這是我的改進版本,適用於長字符串(使用至少 50,000 個單詞進行測試)並將選擇滾動到 textarea 的中心:

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

基於@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);

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> 

我在這里發布了一個答案:

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

它與 jsut 一個需要的規則完美配合:在 textarea 的 css 中設置行高!

它僅通過進行一些簡單的數學計算來計算要滾動到的單詞的位置,並且在我的所有實驗中都運行良好!

請隨時向我詢問有關代碼的任何問題!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM