Javascript IE文本范围选择方法工作不正常

Javascript IE文本范围选择方法工作不正常,javascript,internet-explorer,Javascript,Internet Explorer,contentEditable设置为true的IE文档出现异常问题。对位于块元素前面的文本节点末尾的区域调用select(),会导致选择向右移动一个字符,并显示在不应显示的位置。我向微软提交了一个针对IE8的bug。如果可以的话,请投票支持这个问题,这样它就可以得到解决 我已经编写了一个测试用例来演示其效果: <html> <body> <iframe id="editable"> <html> <b

contentEditable设置为true的IE文档出现异常问题。对位于块元素前面的文本节点末尾的区域调用select(),会导致选择向右移动一个字符,并显示在不应显示的位置。我向微软提交了一个针对IE8的bug。如果可以的话,请投票支持这个问题,这样它就可以得到解决

我已经编写了一个测试用例来演示其效果:

<html>
  <body>
    <iframe id="editable">
      <html>
        <body>
          <div id="test">
            Click to the right of this line -&gt;
            <p id="par">Block Element</p>
          </div>
        </body>
      </html>
    </iframe>
    <input id="mytrigger" type="button" value="Then Click here to Save and Restore" />
    <script type="text/javascript">
        window.onload = function() {
            var iframe = document.getElementById('editable');
            var doc = iframe.contentDocument || iframe.contentWindow.document;

            // An IFRAME without a source points to a blank document.  Here we'll
            // copy the content we stored in between the IFRAME tags into that
            // document.  It's a hack to allow us to use only one HTML file for this
            // test.
            doc.body.innerHTML = iframe.textContent || iframe.innerHTML;

            // Marke the IFRAME as an editable document
            if (doc.body.contentEditable) {
                doc.body.contentEditable = true;
            } else {
                var mydoc = doc;
                doc.designMode = 'On';
            }

            // A function to demonstrate the bug.
            var myhandler = function() {
                // Step 1 Get the current selection
                var selection = doc.selection || iframe.contentWindow.getSelection();
                var range = selection.createRange ? selection.createRange() : selection.getRangeAt(0);

                // Step 2 Restore the selection
                if (range.select) {
                    range.select();
                } else {
                    selection.removeAllRanges();
                    selection.addRange(range);
                    doc.body.focus();
                }
            }

            // Set up the button to perform the test code.
            var button = document.getElementById('mytrigger');
            if (button.addEventListener) {
                button.addEventListener('click', myhandler, false);
            } else {
                button.attachEvent('onclick', myhandler);
            }
          }
    </script>
  </body>
</html>

单击此行的右侧-
块元素

window.onload=函数(){ var iframe=document.getElementById('editable'); var doc=iframe.contentDocument | | iframe.contentWindow.document; //没有源的IFRAME指向一个空白文档 //将我们存储在IFRAME标记之间的内容复制到 //允许我们仅使用一个HTML文件进行此操作是一种黑客行为 //测试。 doc.body.innerHTML=iframe.textContent | | iframe.innerHTML; //将IFRAME标记为可编辑文档 如果(单据体内容可编辑){ doc.body.contentEditable=true; }否则{ var mydoc=doc; doc.designMode='On'; } //一个演示bug的函数。 var myhandler=function(){ //步骤1获取当前选择 var selection=doc.selection | | iframe.contentWindow.getSelection(); var range=selection.createRange?selection.createRange():selection.getRangeAt(0); //步骤2:恢复选择 如果(范围选择){ range.select(); }否则{ selection.removeAllRanges(); 选择。添加范围(范围); doc.body.focus(); } } //设置按钮以执行测试代码。 var button=document.getElementById('mytrigger'); if(按钮。addEventListener){ addEventListener('click',myhandler,false); }否则{ attachEvent('onclick',myhandler); } }
该问题在myhandler函数中公开。这就是我所做的,在保存和恢复选择之间没有第3步,但光标会移动。除非选择为空(即,我有一个闪烁的光标,但没有文本),否则这种情况似乎不会发生,而且只有当光标位于块节点前面的文本节点的末尾时才会发生

看起来范围仍然在正确的位置(如果我在范围上调用parentElement,它将返回div),但是如果我从当前选择中获得一个新的范围,那么新的范围位于段落标记内,这就是它的parentElement


我如何解决这个问题,并在internet explorer中始终保存和恢复所选内容?

我最近在一个网站工作,该网站使用Microsoft CMS和“MSIB+包”控件,其中包括在internet explorer中运行的所见即所得编辑器

我似乎记得编辑器客户端Javascript中的一些注释,它们与IE中的这个bug和Range.Select()方法特别相关

不幸的是,我不再在那里工作了,所以我无法访问Javascript文件,但也许您可以从其他地方获得它们


祝你好运

我进行了一些挖掘&不幸的是,我看不到解决方法。。。尽管在调试javascript时我注意到了一件事,但问题似乎实际上是范围对象本身,而不是后续的
range.select()
。如果查看
selection.createRange()
返回的range对象上的值,则父dom对象可能是正确的,但定位信息已经指向下一行的开头(即offsetLeft/Top、boundingLeft/Top等已经错误)

根据这些信息,而且,我认为你在IE上运气不好,因为你只能访问微软的TextRange对象,它看起来已经坏了。根据我的实验,您可以移动范围并将其精确定位在它应该位于的位置,但一旦这样做,范围对象会自动向下移动到下一行,甚至在您尝试
.select()
它之前。例如,将此代码放在步骤1和步骤2之间可以看到问题:

if (range.boundingWidth == 0)
{
    //looks like its already at the start of the next line down...
    alert('default position: ' + range.offsetLeft + ', ' + range.offsetTop);
    //lets move the start of the range one character back
    //(i.e. select the last char on the line)
    range.moveStart("character", -1);
    //now the range looks good (except that its width will be one char);
    alert('one char back: ' + range.offsetLeft + ', ' + range.offsetTop);
    //calculate the true end of the line...
    var left = range.offsetLeft + range.boundingWidth;
    var top = range.offsetTop;
    //now we can collapse back down to 0 width range
    range.collapse();
    //the position looks right
    alert('moving to: ' + left + ', ' + top);
    //move there.
    range.moveToPoint(left, top);
    //oops... on the next line again... stupid IE.
    alert('moved to: ' + range.offsetLeft + ', ' + range.offsetTop);
}
因此,不幸的是,当您再次选择时,似乎没有任何方法可以确保范围位于正确的位置

显然,通过将步骤2更改为以下内容,上面的代码有一个简单的修复:

// Step 2 Restore the selection
if (range.select) {
    if (range.boundingWidth > 0) {
        range.select();
    }
} else {
    selection.removeAllRanges();
    selection.addRange(range);
    doc.body.focus();
}
但据推测,您实际上希望在实际操作中的步骤1和步骤2之间执行一些操作,这涉及到移动选择,因此需要重新设置它。但以防万一。:)


所以,我所能做的就是去投票给你创造的bug。。。希望他们能解决这个问题。

我想出了一些方法来处理这样的IE范围

如果您只想保存光标所在的位置,然后将其还原,则可以使用pasteHTML方法在光标的当前位置插入一个空白范围,然后使用moveToElementText方法将其再次放回该位置:

// Save position of cursor
range.pasteHTML('<span id="caret"></span>')

...

// Create new cursor and put it in the old position
var caretSpan = iframe.contentWindow.document.getElementById("caret");
var selection = iframe.contentWindow.document.selection;
newRange = selection.createRange();
newRange.moveToElementText(caretSpan);
要恢复光标,请将其设置为开头,然后将其移动到指定的字符数:

var newRange = selection.createRange();
newRange.move('sentence', -1000000);
newRange.move('character', cursorPosition);

希望这有帮助。

也许我误解了,但是如果我单击第一行的右侧,我的光标已经立即出现在第二行的开头,所以这不是TextRange的问题,对吗

添加doctype,使测试页面以标准模式而不是怪癖模式呈现,可以修复这一问题
var newRange = selection.createRange();
newRange.move('sentence', -1000000);
newRange.move('character', cursorPosition);