为什么IE's插入符在文本输入中的位置不等于字符串索引?解决方法是什么?

Why doesn't IE's caret position in a text input equal the string index? What's the workaround?

本文关键字:不等于 位置 字符串 索引 方法 解决 是什么 输入 IE 插入 文本      更新时间:2023-09-26

我并不感到惊讶,但我发现IE8在从文本<input><textarea>检索插入符号位置方面的行为与Chrome和Firefox非常不同。虽然Chrome和Firefox报告插入符号位置类似于字符串值中的索引,但IE8没有。

首先,以下是我在Chrome/Firefox和IE中分别用于检索插入符号位置的函数:

function getCaretPosGecko(txtbox) {
    return txtbox.selectionStart;
}
function getCaretPosIE(txtbox) {
    var range, rangeCopy;    
    txtbox.focus();
    range = document.selection.createRange();    
    if (range !== null) {
        rangeCopy = range.duplicate();
        rangeCopy.moveToElementText(txtbox);
        rangeCopy.setEndPoint('EndToStart', range);    
        return rangeCopy.text.length - range.text.length;
    } else {
        return -1;
    }
}

据我所知,我实现的函数是相当标准的。现在,假设我有一个<textarea>,我在第一行输入"a",在第二行输入"b",没有其他内容。上面的代码报告了Chrome和Firefox中给定标准的以下插入符号位置:

--------------------------------------------------------------------
| I put the caret...       | Code reports caret at position...     |
--------------------------------------------------------------------
| 1st line, after the "a"  | 1 (As expected)                       |
| 2nd line, before the "b" | 2 (As expected)                       |
| 2nd line, after the "b"  | 3 (As expected)                       |
--------------------------------------------------------------------

在IE8中,不幸的是结果非常不同:

--------------------------------------------------------------------
| I put the caret...       | Code reports caret at position...     |
--------------------------------------------------------------------
| 1st line, after the "a"  | 1 (As expected)                       |
| 2nd line, before the "b" | 1 (Maybe it doesn't count new lines?) |
| 2nd line, after the "b"  | 4 (Now, it seems to include 'r'n?)    |
--------------------------------------------------------------------

我假设IE在第三种情况下的计算中包括"'r'n",但为什么不包括它的第二种情况?

更重要的是,我可以做些什么来解决这个差异?我需要知道插入符号在文本框的字符串值内做一些字符串操作。我的第一个想法是在插入符号之前通过"'r'n"的数量来抵消插入符号在IE中的位置,但如果插入符号位于一行的开头或结尾,这将不起作用。

下面是一个工作示例:http://jsfiddle.net/FishBasketGordo/ExZM9/

编辑: @Tim Down下面的回答几乎是正确的。我确实需要做一些修改。下面的函数返回与其Gecko模拟完全相同的结果:

function getCaretPosIE(txtbox) {
    var caret, normalizedValue, range, textInputRange, len, endRange;    
    txtbox.focus();
    range = document.selection.createRange();    
    if (range && range.parentElement() == txtbox) {
        len = txtbox.value.length;
        normalizedValue = txtbox.value.replace(/'r'n/g, '');
        textInputRange = txtbox.createTextRange();
        textInputRange.moveToBookmark(range.getBookmark());
        endRange = txtbox.createTextRange();
        endRange.collapse(false);
        if (textInputRange.compareEndPoints("StartToEnd", endRange) > -1) {
            caret = txtbox.value.replace(/'r'n/g, ''n').length;
        } else {
            caret = -textInputRange.moveStart("character", -len);
            caret += normalizedValue.slice(0, start).split("'n").length - 1;
        }
    }
}
以下是更正后的工作示例:http://jsfiddle.net/FishBasketGordo/uXWXF/

相对于文本区的value属性获得插入符号位置在IE中并不简单,因为您遇到了换行问题。我花了一些时间研究它,并提出了我认为最好的方法。我在Stack Overflow上发表过几次。下面是一个例子:

IE's document.selection.createRange不包括前后空行