【问题标题】:Setting the caret position to an empty node inside a contentEditable element将插入符号位置设置为 contentEditable 元素内的空节点
【发布时间】:2011-05-03 01:34:02
【问题描述】:

我的任务是设置一个文本插入符号以显示在 contentEditable div 内的空跨度节点内。

以下内容在 Firefox 3.6 上没有问题:

<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
        <script type="text/javascript" src="js/jquery-1.4.3.min.js">
        </script>
        <style>
            #multiple {
                border: 1px solid #ccc;
                width: 800px;
                min-height: 20px;
                padding: 5px;
                outline: none;
            }
        </style>
        <script>
            $(document).ready(function(){
                var contentEditable = document.getElementById('multiple');
                var lastItem = contentEditable.getElementsByTagName('span').item(2);
    
                var selectElementText = function(el, win){
                    win = win || window;
                    var doc = win.document, sel, range;
                    if (win.getSelection && doc.createRange) {                    
                        range = doc.createRange();
                        range.selectNodeContents(el);
                        range.collapse(false);
                        sel = win.getSelection();
                        sel.removeAllRanges();
                        sel.addRange(range);
                    }
                    else 
                        if (doc.body.createTextRange) {
                            range = doc.body.createTextRange();
                            range.moveToElementText(el);
                            range.select();
                        }
                }

                contentEditable.focus();
                selectElementText(lastItem);
            });
        </script>
        <title>Range Selection Tasks (Make Me Want to Cry)</title>
    </head>
    <body>
        <div id="multiple" contentEditable="true">
            <span style="color:red">First</span><span style="color:green">Second</span><span style="color:blue"></span>
        </div>
    </body>
</html>

...但在 Webkit 和 IE 上,焦点设置为 倒数第二个 跨度。不知道为什么。如果我在最后一个跨度内放一个空格,它会起作用,但我会得到一个字符范围选择。

话虽如此,如果插入符号位于开头,则可以在最后一个节点中使用空格。

对此的任何帮助将不胜感激。提前谢谢你。

【问题讨论】:

    标签: javascript text cross-browser contenteditable


    【解决方案1】:

    IE 的选择/范围模型基于文本内容的索引,不考虑元素边界。我相信在没有文本的内联元素内设置输入焦点可能是不可能的。当然,对于您的示例,我无法通过单击或箭头键在最后一个元素内设置焦点。

    如果您将每个跨度设置为display: block,它几乎可以工作,尽管仍然存在一些非常奇怪的行为,这取决于父项中是否存在空格。使用浮动、内联块和绝对位置等技巧破解显示以使其看起来内联,使 IE 将每个元素视为一个单独的编辑框。彼此相邻的相对定位的块元素可以工作,但这可能是不切实际的。

    如果让你感觉好点,IE9 终于解决了这个不愉快的问题,采用了标准范围模型。 (万岁!)

    如果插入符号位于最开始,则可以在最后一个节点中包含空格。

    那么,我可能会这样做,除非 IE 选择专家能想到更好的方法。 (打电话给 Tim Down!)

    【讨论】:

    • 感谢您的提示和深思熟虑的回答。你不会相信我在试图让它发挥作用时尝试了多少不同的黑客和变通方法。实际上,如果您有 IE 的经验,您可能会有一个不错的想法。很高兴听到 IE9 终于采用了标准模型。运气好的话,我应该在 2019 年之前迁移所有用户...
    • 您好!我很确定不可能将插入符号放在 IE 中的空内联元素中。更一般地说,在 IE 中,不可能将插入符号放在元素内第一个文本节点的开头。这在 WebKit 中也是如此:bugs.webkit.org/show_bug.cgi?id=15256#c4。我认为添加空格是最好的。我已诉诸于在文本节点的开头插入 Unicode BOM 字符(U+FEFF,在所有主要浏览器中呈现为零宽度),这可行,但当插入符号移动到其他地方时,您将面临删除 BOM 的后勤噩梦。
    • 确实如此。您的指导和蒂姆鼓励我认输,只是以编程方式添加空格。谢谢你们。
    • @TimDown 确认!我几乎设法使用.move() 破解了这个问题。我设法得到一个 TextRange 来 report 它位于内联元素中(当它在一开始时)jsfiddle.net/GJLPN/13 不幸的是,键入不会将文本放在节点内。嗯嗯。
    • 它已经破解了!! jsfiddle.net/GJLPN/31 在元素的开头添加一个字符,使用上述移动技术,使用.moveEnd() 选择字符,然后将.text 设置为“”似乎可以解决问题:)。不过,这种技术似乎不适用于空的内联元素。
    【解决方案2】:

    我找到了 Webkit 的解决方法,不知道之前是否有人发现过这个,但不是以编程方式附加一个零宽度的空间,您可以在元素的后伪选择器中使用 css3 内容属性做同样的事情你想把插入符号放进去。这样做的好处是多余的字符不会出现在 DOM 中,并且用户无法在它之间导航插入符号。所以基本上不需要清理。

    要使其适用于内容可编辑元素的任何子元素,它应该是这样的:

    #mycontenteditableelement *:after {
        content: '\200B';
    }
    

    我没有完全检查,但我怀疑这是一个完整的解决方法。

    【讨论】:

    • 使用风险自负:来自 webkit 的某个人建议不要使用这种技术,因为在 contenteditable 区域中对使用 after psuedo-selector 的支持很差,并且可能导致 webkit 崩溃或达到不一致的状态。同样,请参阅 webkit bugzilla:bugs.webkit.org/show_bug.cgi?id=15256
    【解决方案3】:

    使用 inline-block 对 contenteditable 内的元素应用最小高度和最小宽度可以做到一些好处,尽管这种影响会产生意想不到的副作用:

    #multiple * {
        min-height: 1em;
    }
    span, b, strong, i, em, a, etc {
        display: inline-block;
        min-width: 1em;
        background-color: hsla(0, 50%, 50%, .5); /* this is only a visual aid; discard @ will */
        vertical-align: middle; /* so elements w/ inline-block align w/ text correctly */ 
    }
    

    你会发现仍然存在问题,但如果你愿意为一小部分其他问题牺牲一些问题,这可能会很好。

    【讨论】:

      【解决方案4】:

      将元素的innerHTML 设置为零宽度字符:

      ('element').innerHTML = '&#200B';
      

      现在carret可以去那里了。

      【讨论】:

      • 这很好用;我在标记中使用了&amp;#8203;&amp;#200B; 渲染不正确)。
      • 这个答案混淆了 html 和 unicode 标识符。使用“​”或 "\u200B" 表示零长度不间断空格。
      • 确保在用户输入真实文本后删除零宽度字符。除非用户在使用箭头键浏览文本时会注意到零宽度字符的存在。
      【解决方案5】:

      对我来说,将 contenteditable div 的内容设置为 &lt;br&gt; 有效。我尝试将其设置为nbsp;,但这会在我开始编辑之前在 div 中创建额外的字符空间。

      希望这会有所帮助。

      【讨论】:

        【解决方案6】:

        聚会有点晚了,但我使用了 Unicode 零宽度无间断空间 (&amp;#65279;)。然后在用户输入发生后调用的事件中,删除零宽度无中断空间。

        我在使用 Unicode 空间问题时遇到了很多问题,主要是糟糕的用户体验。这可以防止用户知道存在问题。

        【讨论】:

          猜你喜欢
          • 2016-11-30
          • 2010-11-14
          • 2011-06-17
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多