【问题标题】:HTML contenteditable with non-editable islands带有不可编辑岛的 HTML 内容可编辑
【发布时间】:2013-01-14 22:48:38
【问题描述】:

我有一种基于浏览器的所见即所得编辑器,用户可以在其中编辑文档模板。

Document-template 是一个普通的 html,带有一些特殊的“合并代码占位符”。通过将这些占位符替换为来自 DB 的数据,此类模板得到“实例化”。这给出了最终文档 - 模板的一个实例。

我目前的做法是这样的:

<div contenteditable>
  Sample template with <input type=button class="mergecode" value="MergeCode1">.
</div>

(在线示例:http://jsfiddle.net/tFBKN/

在这种情况下,输入是不可编辑的,并且表现为一个实心块——这正是我所需要的。 用户可以通过单击 DEL 或 BACKSPACE 作为任何其他字符等来删除此类合并代码。通过为此类 input.mergecode 设置适当的 CSS,我可以实现我想要的外观。

但是通过这种方法,我在三个不同的 UA 中遇到了三个不同的问题:

  • IE - CSS { font:inherit } 在那里根本不起作用,所以如果输入在 &lt;b&gt; 中,就像这里的 &lt;b&gt;&lt;input value="test"&gt;&lt;/b&gt; 一样,它不会继承任何字体样式。
  • FF - 包含 &lt;input&gt; 元素的片段副本会从剪贴板内容中删除该输入,因此进一步的粘贴操作会插入所有内容,但不会插入输入。
  • GC - 在&lt;input&gt; 产生奇怪的结果后立即点击 {BACKSPACE} (bug)

所以我正在寻找关于如何在 HTML 中表示不可编辑的内联块类似“岛”的其他想法。

到目前为止我尝试过的其他方法:

  • &lt;span contenteditable="false"&gt;MergeCode1&lt;/span&gt; - 它不起作用,因为大多数 UA 从选择中删除了此类节点。因此,不可能在包含此类跨度的选择之上应用&lt;b&gt;&lt;i&gt;

还有其他想法吗?

【问题讨论】:

  • 不可能。 contenteditable 影响所有子元素。删除后可以用JS替换。
  • @Mooseman 抱歉,究竟是什么不可能?
  • @Mooseman 的评论有误; contenteditable 可以被子元素覆盖,如示例&lt;span contenteditable="false"&gt;MergeCode1&lt;/span&gt;。正如问题所解释的那样,这种自然方法不适用于选择(例如,三次单击不会选择整个块)。
  • 试试这个代码:&lt;div style="background:#000; color:#FFF" contenteditable=true&gt; Hello, world! &lt;span contenteditable="false" style="font-weight:bold"&gt;Unedtiable&lt;/span&gt; Hello, world! &lt;/div&gt; 如你所见,span 仍然可以被移除。无法编辑文本“不可编辑”,但用户可以将&lt;span&gt; 作为一个整体删除。 Chrome 开发工具显示整个块已从 DOM 中删除。
  • @Mooseman,正如我所说,我已经尝试过 contenteditable="false"。如果您需要在此类岛的顶部应用像&lt;b&gt; 这样的跨度,则它不起作用。试试这个:jsfiddle.net/RYsvZ/1,例如选择带有 MergeCode1 的文本,然后单击 CTRL-I。您将看到斜体文本,但不是 MergeCode1。使用 DOM 检查器查看问题。

标签: html contenteditable


【解决方案1】:

我是 CKEditor 开发人员。我们对嵌套只读元素(即placeholder 插件和我们目前正在开发的功能#9764)有一些经验,但我没有好消息。如果你想拥有一致的外观和感觉,你必须手动处理每一个行为。没有任何技巧可以修复浏览器。而且很多事情(比如在 GC 输入周围发生的奇怪事情)似乎都无法解决。

【讨论】:

  • 感谢您的回复,看来这不仅仅是我的问题。这一事实使这种果皮稍微不那么苦,但仍然如此。不过感谢您的回答。
  • @Reinmar 迟到了,但是......你有没有找到解决这个问题的方法?干杯!
【解决方案2】:

还有一个看起来很有希望的想法:

将空跨度与::before { content:"caption"; } 一起使用应该会产生不可编辑的块,在 DOM 中表示为内部没有插入符号位置的节点。

你可以在这里试试http://jsfiddle.net/TwVzt/1/

但这种方法并非没有问题(在我的例子中):没有办法使用 style DOM 属性声明 ::before 内联,因此应该在 CSS 中预先声明整个集合。 但是我拥有的一组合并代码非常大,在某些用例中甚至是完全未知的。叹息。

如果有人有更好的情况(已知的代码集),请把这个食谱放在这里。

【讨论】:

  • 工作就像一个魅力!使用data-attributes::before 中包含动态内容。
  • 是的,这是一个不错的解决方案。我还在这里找到了这种技术:“HTML5 数据属性”:hacks.mozilla.org/2012/10/… 和该页面上的视频:youtube.com/watch?v=On_WyUB1gOk(6 分钟)
  • 非常感谢!这种通过数据属性结合动态文本的方法为我扫清了一个主要障碍。
  • 为这篇文章和 cmets 添加更多亮点:&lt;span data-something="awesome"&gt;&lt;/span&gt;span:before{content:attr(data-something);} 很容易创建一个 &lt;style&gt;...&lt;/style&gt; 块,其中包含所有使用 JS 动态生成的伪内容和样式,然后附加到头来。
  • Ctrl-a可以删除元素。
【解决方案3】:

我知道它是一个旧线程,我遇到了类似的问题。只需要几个不可编辑的跨度在可编辑的 div 中。最终实现了一个像...一样的HACK-AROUND

$('#testDiv').on('keydown', function(e) { 
    var targetNode = getSelectionStart();
    if(targetNode != undefined && targetNode.nodeType === 1 && targetNode.nodeName == 'SPAN')    
    {
      var nodeHtmlString = targetNode.outerHTML;

      if(~nodeHtmlString.indexOf("nonEditable"))
      {
        e.preventDefault();
        e.stopPropagation();
      }
    }
});

function getSelectionStart() {
 var node = document.getSelection().anchorNode;
 return (node.nodeType == 3 ? node.parentNode : node);
}

https://jsfiddle.net/fxmb3nL6/20/完成小提琴

【讨论】:

    【解决方案4】:

    下面的解决方案 - 有一个小警告。但首先——你们太棒了!
    我不是 JS 或 HTML 专家,但我也不知道 jsfiddle.net。 因此,阅读您的 cmets 以及其他在线搜索,以及对 jsfiddle 的一些测试,我创建了以下有效的代码。

    <pre><code>
    <div contenteditable="false" class="editor" readonly="true" UNSELECTABLE="ON">
        Sample template with <span class="mergecode test1" />.
        <span contenteditable> editable </span>
        <font color=red><span UNSELECTABLE="ON" contenteditable="false" readonly="true"
         UNSELECTABLE="ON">  uneditable1 </span></font>
        <span contenteditable> editable2 </span>
        <font color=red><span contenteditable=false readonly="true" UNSELECTABLE="ON"> uneditable3</span></font>  
        <span contenteditable> editable4 </span>
        <span contenteditable="false" readonly="true" UNSELECTABLE="ON"> uneditable5 </span>
    < /div>
    </code></pre>
    

    如果你把它放到 chrome 上的 jsfiddle 中,你会看到它在 chrome 中工作(和 IE 和 FF,但有点不同),但似乎有一个小警告。

    需要注意的是您的键绑定对 Backspace 的作用!就我而言,当我选择一个不可编辑的短语并在 chrome 中按退格键时,它似乎会刷新,或者执行“转到最后一页”! 我将前两个 undeditbles 设为红色(留下最后一个黑色),以便您可以看到会发生什么。我在 Chrome、FF 和 IE 中的 jsfiddle 上对其进行了测试。一切似乎都采取了正确的行动,给予或接受退格问题。

    我认为这是它的工作逻辑。 第一个 Div 是顶级父级,它是 contenteditable="false"。所以它下面的所有东西都应该是不可编辑的。除了其中具有跨度 contenteditble="true" 的孩子之外,它们变得可编辑。所以你从你的父母那里继承,但是你可以作为一个孩子覆盖。

    我也把标签 readonly="true" UNSELECTABLE="ON" 因为我在某个地方读到过它们。而且还需要更多的测试!!!请注意,我必须将 Font... 放在跨度之外,否则它将不起作用。但在 IE 中它工作得很好。 uneditables 是我告诉他们的任何颜色,没有多少单、双或三次单击会选择 jsfiddle 中的 uneditbles !!! :-) 对于 Chrome,单击什么也没做,双击选择了不可编辑的,并且使用退格键它有点疯狂!似乎会转到上一页。 FF的事情有点疯狂!双击选中不可编辑的和之前的可编辑的!不知道为什么。

    如果有人能找出并写下 Chrome 和 FF 的问题,那就太好了。如果在 Chrome 和 FF 中双击或任意数量的快速点击也不起作用,那就太好了。我想再次强调跨度......似乎必须在不可编辑和字体旁边......在跨度之外。

    希望这一切都有意义。

    【讨论】:

    • 用它在文本编辑器中包含内联变量,所以这对我来说完全有用,谢谢!
    【解决方案5】:

    这是我在项目中使用的解决方案:

    <div>
      <span contenteditable>Editable text</span> <span> - Non editable text</span>
    </div>
    

    用对应的CSS看看效果:

    div {
      border: 1px solid black;
      display: inline-block;
      max-width: 200px;
    }
    

    结果如下:http://www.cssdesk.com/rULJM

    【讨论】:

    • 是的,但您正在解决完全不同的任务:不可编辑文本中的可编辑岛。
    【解决方案6】:

    对于 IE,试试这个:

    <span contenteditable="true">Uneditable</span>
    

    注意 contenteditable 属性的反向值!它违背了所有常识,但它确实有效——至少在 IE8 和 IE9 中是这样。您可以移动和复制/粘贴这个不可编辑的元素。然而,它远非完美。例如。如果将包含不可编辑元素的区域加粗,这也会感染不可编辑元素的内容。所以你可能不得不使用一些脚本来保持元素的完整性。还设置 contenteditable="true" 将使用调整大小手柄装饰不可编辑的元素。您可以通过设置 unselectable="on" 再次关闭它们,但这将防止对象被拖动。同样,您可能不得不依赖恢复宽度和高度的脚本。

    【讨论】:

    • 不幸的是,这种方法在 GC 和 FF 中不起作用 - 如果您选择包含此类 &lt;span&gt; 的文本并调用 document.execCommand('bold') 以将 &lt;b&gt; 应用于选择,则跨度将从选择。你会看到这样的东西:&lt;b&gt;text before&lt;/b&gt;&lt;span contenteditable=false&gt;Test&lt;/span&gt;&lt;b&gt;text after&lt;/b&gt;.
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-06
    • 1970-01-01
    • 2011-10-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多