如何在两个 div 之间的 contenteditable div 中设置插入符号/光标位置

考虑以下内容可编辑的 div.

如果我将光标定位在两个 div 之间并开始输入,文本会变为粗体,而不是在两个 div 之间插入新的文本节点.如果您回到家并尝试在第一个 div 前面键入一些内容,也会发生同样的情况.它成为第一个 div 的一部分.

如果我检查从选择返回的范围的 startContainer,我会得到其中一个 div 的内容,而不是我期望的空文本节点.

$( '#EDITABLE' ).focus();var selection = window.getSelection();var range = document.createRange();var div = $('#div2').get(0);range.setStartBefore(div);range.collapse(true);selection.removeAllRanges();选择.addRange(范围);//光标现在应该在 div1 和 div2 之间range = window.getSelection().getRangeAt(0);console.log("返回的范围对象为:", range);//在内容可编辑的 div 中输入一些内容.为什么会来//加粗因为光标应该在 div 之间?它是//将光标定位在前一个 div 的末尾.我想要//定位到 div 之间的位置.怎么样?

div.content {显示:内联块;字体粗细:粗体;}

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.8.3/jquery.min.js"></脚本><div contenteditable="true" id="EDITABLE"><div class="content" id="div1">div1 的内容</div><div class="content" id="div2">div 2 的内容</div></div>

原始 jsfiddle:http://jsfiddle.net/9ZZpX/3/

问题是为什么会发生这种情况?如何选择 div 之间的位置,以便当我输入内容时它不会加粗?(显然我可以添加一个空格来解决这个问题,但这很丑.)

如果您在状态更新框中输入@mention 并按 HOME,您可以在 Facebook 上看到此功能正常工作.如果您键入文本将不会突出显示.

我唯一能想到的就是拦截按键并以编程方式插入文本节点,但这看起来很难看.

我疯狂地搜索,但找不到任何参考资料来说明这应该如何工作.显然有一些我不明白的地方,并且这方面的文档确实缺乏.

(我也想做的是检测光标何时要进入其中一个 div 并跳过它.如果两个 div 彼此相邻,则光标会跳转到其中一个divs,它搞砸了工作.)

有关我正在尝试做的事情的更多信息:http://a-software-guy.com/2012/12/the-horrors-of-cursor-positioning-in-contenteditable-divs/

解决方案

浏览器对此不一致.Firefox 将允许您将插入符号定位在比大多数浏览器更多的位置,但 WebKit 和 IE 都对有效插入符号位置有明确的想法,并将修改您添加到选择中的范围以符合最近的有效位置.这确实是有道理的:具有不同的文档位置,因此对于相同的视觉插入符号位置的行为会让用户感到困惑.然而,这是以开发人员的不灵活为代价的.

这在任何地方都没有记录.当前选择规范对此只字未提,主要是因为不存在规范当浏览器实现其选择 API 并且当前规范没有统一的行为记录时.

一种选择是按照您的建议拦截 keypress 事件,尽管当用户使用编辑或上下文菜单粘贴内容时这无济于事.另一种方法是使用鼠标和键事件来跟踪选择,创建具有例如零宽度空格字符的元素以放置插入符号,并在必要时将插入符号放置在这些元素中.正如你所说,丑陋.

Consider the following contenteditable div.

<div contenteditable="true">
<div>bold text</div><div>bold text</div>
</div>

If I position the cursor between the two divs and start typing the text comes out bold instead of inserting a new text node between the two divs. The same happens if you hit home and try to type something in front of the first div. It becomes part of the first div.

If I inspect the startContainer of the range that's returned from the selection, I get the content for one of the div's instead of an empty text node as I would expect.

$( '#EDITABLE' ).focus();

var selection = window.getSelection();

var range = document.createRange();

var div = $('#div2').get(0);

range.setStartBefore(div);
range.collapse(true);

selection.removeAllRanges();
selection.addRange(range);

// cursor should now be between div1 and div2

range = window.getSelection().getRangeAt(0);

console.log("range object returned is: ", range);

// type something into the content editable div. why is it coming
// up bold since the cursor should be between the divs? it's 
// positioning the cursor at the end of the previous div. I want to
// target the spot between the divs. how?

div.content {
  display: inline-block;
  font-weight: bold;
}

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<div contenteditable="true" id="EDITABLE">
  <div class="content" id="div1">Content for div1</div>
  <div class="content" id="div2">content for div 2</div>
</div>

Original jsfiddle: http://jsfiddle.net/9ZZpX/3/

The question is why does this happen? How can I select the spot between the divs so that when I type something it does not bold? (Obviously I can add a space and that works around the problem but that's quite ugly.)

You can see this working correctly at Facebook if you enter an @mention in a status update box and press HOME. If you type the text will not get highlighted.

The only thing I've been able to think of is intercepting the keypress and inserting a text node programmatically but that seems ugly.

I searched like crazy and can't find any references that document how this is really supposed to work. There is obviously something that I do not understand and the documentation is really lacking in this area.

(What I want to be able to do as well is detect when the cursor is about to enter one of these divs and jump over it. If the two divs are right next to each other, the cursor jumps into one of the divs and it mucks up the works.)

More info on what I'm trying to do: http://a-software-guy.com/2012/12/the-horrors-of-cursor-positioning-in-contenteditable-divs/

解决方案

Browsers are inconsistent on this. Firefox will let you position the caret in more positions than most browsers but WebKit and IE both have definite ideas about valid caret positions and will amend a range you add to the selection to conform to the nearest valid position. This does make sense: having different document positions and hence behaviours for the same visual caret location is confusing for the user. However, this comes at the cost of inflexibility for the developer.

This is not documented anywhere. The current Selection spec says nothing about it, principally because no spec existed when browsers implemented their selection APIs and there is no uniform behaviour for the current spec to document.

One option would be to intercept the keypress event as you suggest, although this will not help when the user pastes in content using the edit or context menus. Another would be to keep track of the selection using mouse and key events, create elements with, say, a zero-width space character for the caret to be placed in and place the caret in one those elements when necessary. As you say, ugly.

相关文章