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