在ContentEditable中使用Shadow DOM来创建受保护的文本块

时间:2017-03-30 13:47:48

标签: javascript html contenteditable web-component shadow-dom

最近,我一直在使用ContentEditable开发一个简单的编辑器。应用程序的要求很简单,但能够插入受正常编辑操作保护的文本块除外。

这些文本块无法编辑,并且必须表现为单个字符,以便将光标移动或删除它们。

生成的HTML的示例如下所示:

<div id="editor" contenteditable style="height: 400px; border: 1px solid black; margin: 4px; padding: 4px; overflow:auto;">
  "This is standard text with a "
    <span class="attrib">
      #shadow-root
        "PROTECTED"
      "_"
    </span>
  " block"
</div>

虽然这提供了我需要的受保护文本部分,但它有一些我无法解决的主要问题:

  • 阴影DOM元素后面的文本不显示。
  • 光标根本不会在shadowDOM元素中移动。

有更好的方法可以做到这一点,还是不可能以这种方式使用shadow DOM?

1 个答案:

答案 0 :(得分:5)

解决方案1 ​​

您可以在受保护的元素中强制contenteditable属性为false

&#13;
&#13;
<div id="editor" contenteditable style="height: 100px; border: 1px solid black; margin: 4px; padding: 4px; overflow:auto;">
  "This is standard text with a 
  <span contenteditable="false">PROTECTED</span> 
   block"
</div>
&#13;
&#13;
&#13;

解决方案2

如果您想使用不带contenteditable=false的Shadow DOM:

您可以使用window.getSelection().anchorOffset观察插入位置,并检查位置是否已更改。

如果没有,您必须使用Selection&#39; setBaseAndExtent()将插入符移动到下一个文本节点(如果可能)。

以下是按下[Right Arrow]键时的最小示例:

&#13;
&#13;
editor.querySelector( '.attrib' )
      .attachShadow({mode: 'open' } )
      .innerHTML = 'PROTECTED'
   
editor.addEventListener( 'keydown', onkeydown )

var position = 0 

function onkeydown( ev )
{
  if ( ev.key == "ArrowRight" )
  {
    setTimeout( function ()
    { 
      var sel = window.getSelection()
      if ( position == sel.anchorOffset )
      {
        var anchor = sel.anchorNode 
        if ( anchor.nextSibling && anchor.nextSibling.nextSibling )
        {
          console.warn( 'move next' ) 
          var next = anchor.nextSibling.nextSibling
          sel.setBaseAndExtent( next, 1, next, 1)
        }
      } 
      position = sel.anchorOffset
    } ) 
  }
}
&#13;
.attrib {
    background: lightblue ;
}
  
#editor {
    height: 100px; width:400px; border: 1px solid black; margin: 4px; padding: 4px; overflow:auto
}
&#13;
<div id="editor" contenteditable>"This 
		is standard text with a <span class="attrib">TEST</span> block"
</div>
&#13;
&#13;
&#13;