【问题标题】:Closing <ul /> tags in contenteditable without inserting superfluous tags在 contenteditable 中关闭 <ul /> 标签而不插入多余的标签
【发布时间】:2013-01-23 16:30:24
【问题描述】:

在 contenteditable 中处理无序(或有序)列表让我很头疼。

每当我想通过按 ENTER 两次来结束编辑列表时,浏览器将关闭 &lt;ul /&gt; 但会插入一个 &lt;p /&gt; (Firefox) 或 &lt;div /&gt; (Chrome) 标签,其中包含&lt;br /&gt;
Example here

我的目标是避免使用多余的&lt;p /&gt;&lt;div /&gt;,而只是关闭&lt;ul /&gt;
我试图修改Tim Down's 解决方案,这将阻止浏览器在按下 ENTER 时插入&lt;p /&gt;&lt;div /&gt;,而是插入一个干净的&lt;br /&gt; 标签。
@ 987654323@

不幸的是,当使用该解决方案时,&lt;ul /&gt; 永远不会被浏览器关闭,因为只有&lt;br /&gt; 标记被插入 &lt;li /&gt; 项目。

所以我的问题是:

如何在最后一个空的&lt;li /&gt;上按回车时通过插入节点或粘贴html来主动关闭&lt;ul /&gt;

更新:如果问题还不清楚:我正在寻找一种方法来关闭 &lt;ul /&gt; 而不插入 &lt;p /&gt;&lt;div /&gt; 标签但是只需插入一个好的旧普通 &lt;br /&gt; 代替

【问题讨论】:

  • 你在期待什么? &lt;ul&gt; 是“关闭的”,由于存在; DOM 中没有未关闭的&lt;ul&gt; 这样的东西。当您按两次 Enter 键时,您要求输入 beyond &lt;ul&gt;,并且该空白行必须位于某处,因此浏览器将其放入 &lt;p&gt;
  • 我也偶然发现了这种行为,但我观察到使用 FF6 时没有输入额外的 p-tag - 它只发生在更新的 FF 版本中

标签: javascript jquery contenteditable


【解决方案1】:

与您的尝试类似,我们在用户按 Enter 时修改 contenteditable:Demo

if (window.getSelection) { // w3c
    $('div').keypress(function (e) {
        var sel, node, children, br, range;
        if (e.which == 13) {
            sel = window.getSelection();
            node = $(sel.anchorNode);
            children = $(sel.anchorNode.childNodes);

            // if nothing is selected and the caret is in an empty <li>
            // (the browser seems to insert a <br> before we get called)
            if (sel.isCollapsed && node.is('li') && (!children.length ||
                    (children.length == 1 && children.first().is('br')))) {
                e.preventDefault();

                // if the empty <li> is in the middle of the list,
                // move the following <li>'s to a new list
                if (!node.is(':last-child')) {
                    node.parent().clone(false)
                        .empty()
                        .insertAfter(node.parent())
                        .append(node.nextAll());
                }

                // insert <br> after list
                br = $('<br>').insertAfter(node.parent());

                // move caret to after <br>
                range = document.createRange();
                range.setStartAfter(br.get(0));
                range.setEndAfter(br.get(0));
                sel.removeAllRanges();
                sel.addRange(range);

                // remove <li>
                node.remove();
            }
        }
    });

} else if (document.selection) { // internet explorer
    $('div').keypress(function (e) {
        var range, node, children;
        if (e.which == 13) {
            range = document.selection.createRange();
            node = $(range.parentElement());
            children = $(range.parentElement().childNodes);

            // if nothing is selected and the caret is in an empty <li>
            // (the browser seems to insert a <br> before we get called)
            if (!range.htmlText.length && node.is('li') && (!children.length ||
                    (children.length == 1 && children.first().is('br')))) {
                e.preventDefault();

                // if the empty <li> is in the middle of the list,
                // move the following <li>'s to a new list
                if (!node.is(':last-child')) {
                    node.parent().clone(false)
                        .empty()
                        .insertAfter(node.parent())
                        .append(node.nextAll());
                }

                // insert <br> after list
                br = $('<br>').insertAfter(node.parent());

                // move caret to after <br>
                range = document.body.createTextRange();
                range.moveToElementText(br.get(0));
                range.collapse(false);
                range.select();

                // remove <li>
                node.remove();
            }
        }
    });
}

请注意,这不处理用户在按 Enter 之前选择了某些内容的情况。如果你想处理这种情况,你需要弄清楚用户是否选择了&lt;li&gt;的全部内容(这似乎不是一个简单的任务),如果是,删除内容并处理它就像用户在空的&lt;li&gt; 中按 Enter 一样。

【讨论】:

  • 似乎工作得很好。我会进一步测试它,并会回复你。现在谢谢!
【解决方案2】:

我理解您的问题,但不清楚为什么会存在这样的要求。这可能有助于澄清这方面。

无论如何,这里有一个想法。为什么不替换或删除空的&lt;div&gt;&lt;p&gt; 标签。

$(document).ready(function(){
    $("div").keyup(function(evt) { 
        $("div, p").filter( function() {
                $this = $(this);
            return !($.trim($(this).text()).length);
        }).replaceWith('<br />');
    });
});

工作示例: http://jsfiddle.net/4xyR2/9/

我注意到的一个问题是contenteditable 使用上述解决方案如何影响光标。我认为 Chrome 和 Firefox 需要 &lt;div&gt;&lt;p&gt; 以便他们可以跟踪光标在 &lt;div&gt; 中的位置。这来自我在测试时的观察,而不是对浏览器如何解释contenteditable的深刻理解。

Chrome (24.0.1312.52 m) 似乎不喜欢替换。我在测试时看到奇怪的光标位置,但它可以工作。 Firefox (17.0.1) 可以很好地处理替换。

【讨论】:

  • 似乎可行,但这是一种解决方法,我想避免很多开销。另外,按两次回车键会失去焦点...
【解决方案3】:

我能在没有 Javascript 的情况下锻炼的最好的东西是

HTML:

<div contenteditable="true">
  <div>asdfasdf</div>
</div>

少:

div[contenteditable=true] {
  outline: none;

  &>p,
  &>div {
      margin: 0 0 0 30px;
      display: list-item;
  }
}

http://jsbin.com/idekix/6/edit

但是这里有一些缺点,

  1. 第一个也是非常大的,Win8 上的 FireFox 18.0.1 代替插入 divp 标记作为新行使用类似双 br 的东西,

  2. 第二次发生在您删除所有内容并开始输入并按 Enter 时,不同浏览器的行为非常不同,Chrome 将第一行作为 contenteditable 容器的纯文本节点插入,然后将每个新行放入 @ 987654333@,Opera 12.12 处理得更好,它永远不允许删除最后一个div 节点,IE9-10 开始跳来跳去,在你重新开始后使用p 标签而不是div(这甚至不是一场灾难,只是不一致),但 FireFox 甚至还没有尝试改变它的 br 行为。还尝试使用 IE10 调试模式检查 IE7-8,它与 Opera 相同,但不是真正的浏览器。

  3. 1234563插入空的li

也就是说,所有测试都是在 Windows 8 64 位平台上完成的,使用 Chrome 24.0.1312.56 m、FireFox 18.0.1、Opera 12.12 和 IE10,通过 IE 调试栏模拟旧版 IE。承认在其他平台/版本上情况可能会有所不同。

综上所述,contenteditable 有很好的浏览器支持范围http://caniuse.com/contenteditable,但是每个浏览器都有自己的实现,这是另一个单独的问题。因此,如果没有跨浏览器 JavaScrpt 的麻烦,您将无法使用它。同样作为我个人的观点,contenteditable 的核心思想更适合像 iframe 的轻量级替换,当它用作浏览器中几乎所有富文本编辑器的元素时。

来自 Mozilla 源 https://developer.mozilla.org/en-US/docs/HTML/Content_Editable的UPD

在 HTML5 中,任何元素都可以编辑。这个特性是很久以前引入的,但现在已经被 WHATWG(html 当前规范)标准化。使用一些 JavaScript 事件处理程序,您可以将您的网页转换为一个完整且快速的富文本编辑器

下一步只是我的谦虚建议。我认为,在您的情况下,可以使用真正的可编辑字段来代替。我在这个 bin http://jsbin.com/ojiyok/7/edit 中所做的非常多的原型版本还有一些需要改进的地方,但看起来它比真正的 conteneditables 具有更多可预测的行为,而且这里的好部分是你可以根据你的需要在所有浏览器中一次更改 UI。

【讨论】:

  • 感谢您的详尽回答,但我该如何退出列表?
  • 你觉得怎么样?反正我喜欢 Opera 的方式,会尝试根据它修改建议
  • @Horen 这里是速写jsbin.com/ojiyok/6 我还不确定你是否对这种解决方案感兴趣,所以不要尝试实施可靠的解决方法
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-01-15
  • 2016-01-05
  • 1970-01-01
相关资源
最近更新 更多