13

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

每当我想通过按ENTER两次来结束编辑列表时,浏览器将关闭<ul />但插入一个<p />(Firefox)或一个<div />(Chrome)标签,其中包含<br />.
这里的例子

我的目标是避免多余的,<p />或者 <div />只是关闭<ul />.
我试图修改Tim Down 的解决方案,这将阻止浏览器插入<p /><div />在按下时ENTER插入一个干净的<br />标签。
这里的例子

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

所以我的问题是:

如何<ul />在最后一个空白处按 enter 时通过插入节点或粘贴 html 来主动关闭<li />

更新:如果问题还不清楚:我正在寻找一种方法来关闭<ul />而不插入<p /><div />标记,但只需插入一个好的旧平原<br />代替

4

3 回答 3

7

与您的尝试类似,我们在用户按 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 之前选择了某些内容的情况。如果你想处理这种情况,你需要弄清楚用户是否选择了整个内容<li>(这似乎不是一个简单的任务),如果是这样,删除内容并将其视为如果用户在一个空的<li>.

于 2013-01-29T10:34:56.590 回答
1

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

无论如何,这是一个想法。为什么不替换或删除空的<div><p>标签。

$(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 需要<div><p>因此他们可以跟踪光标在<div>. 这来自我在测试时的观察,而不是对浏览器如何解释的深刻理解contenteditable

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

于 2013-01-26T04:50:36.417 回答
0

我能在没有 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 代替插入divorp标记作为新行使用类似 double 的东西br

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

  3. 第三,它允许你插入空节点,说到这个 Opera 做得很好,在 Opera http://jsbin.com/uxesez/1/edit中看到这个 bin ,这里的标记更接近原始,它不允许你插入空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 源的 UPD https://developer.mozilla.org/en-US/docs/HTML/Content_Editable

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

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

于 2013-01-31T15:20:25.757 回答