富文本编辑器运行不正常

Rich Text Editor Not Behaving Correctly

我正在尝试在文本字段上创建富文本编辑器。为了尝试这样做,我使用了 Summernote。我让编辑器初始化接近我想要的方式。我真的很希望 airmode 在悬停时表现出来而不是在点击时表现出来。不过,有一个奇怪的行为是我真正的问题。

如此 Fiddle 所示,用户可以在屏幕上的三个编辑器之一中开始输入。但是,一旦您输入 space,文本就会转到输入字段上方的行。它不会留在同一条线上。奇怪的是,输入行正上方的文本不允许进行丰富的编辑。我正在像这样初始化文本字段:

  var optionEditors = $('.option-editor');
  for (var i=0; i<optionEditors.length; i++) {
    $(optionEditors[i]).summernote({
      airMode: true,
      popover: {
        air: [
          ['font', ['bold', 'underline', 'clear']]
        ]
      }
    });
  }

我错过了什么?一切看起来都是正确的。只是行为似乎是错误的。谢谢。

Bootstrap plugins depend on jQuery;如果不先加载它们就会失败:

Plugin dependencies

Some plugins and CSS components depend on other plugins. If you include plugins individually, make sure to check for these dependencies in the docs. Also note that all plugins depend on jQuery (this means jQuery must be included before the plugin files). Consult our bower.json to see which versions of jQuery are supported.

The defer attribute 在您的 jQuery 脚本加载标记中导致它在 之后加载 您在 onload 中调用 addAllElements事件。

defer

此布尔属性设置为向浏览器指示脚本将在文档被解析后执行。由于此功能尚未被所有其他主要浏览器实现,作者不应假设脚本的执行实际上会被推迟。 defer 属性不应该用在没有 src 属性的脚本上。从 Gecko 1.9.2 开始,没有 src 属性的脚本会忽略 defer 属性。但是,在 Gecko 1.9.1 中,如果设置了 defer 属性,甚至内联脚本也会被延迟。

发生这种情况的原因似乎与 jQuery 无关,似乎与 summernote 初始化编辑器的方式有关。您获取的 optional-editor 属性是一个 div 元素并且正在初始化,而不是 input 元素。

接下来发生的是 summernote 然后使用这个 div 并在里面创建几个其他 div 元素,其中 class 像 note-editor, note-dropzone , note-editing-area, 等等。最里面的 div 有一个叫做 note-editable 的 class 并且在这个 div 里面是你的输入元素。 note-editable div 是 summernote 认为实际的富文本编辑器,而不是输入元素。也就是说,您仍然可以单击输入元素并输入您想要的任何内容。

Summernote 在 onkeydown 事件 (see the docs here) 上放置了一些事件监听器,因为它是一个富文本编辑器,它似乎正在检查 spacebar 字符(其中包括 enter 成为一个新的段落)以便它可以在 HTML 中转义它(space 变成 &nbsp;)。因为你在 note-editable div 里面打字,即使你在技术上在 input 元素里面打字,这个按键也会被 summernote 捕捉到,它似乎把转义的 space字符在div里面,不是在输入里面。这导致文本被放置在您的输入元素上方。您会注意到,当您的光标位于输入元素上方时,您可以使用 ctrl+A 来突出显示此可编辑 div 中的所有内容,您甚至可以删除您的输入元素。

我的建议是完全删除输入元素,只使用包含 div 的元素,因为这似乎是最常见的用例场景。您也可以尝试覆盖 onkeydown 事件侦听器并将 space 附加到输入内部,但这似乎是一种非常迂回的方式来尝试解决实际上不需要解决的问题。

编辑: 看起来 summernote 克隆了指定为富文本编辑器的节点,该节点最终将删除所述元素上的所有事件侦听器,包括其子元素,因此您无法在初始化 summernote 之前覆盖文本输入元素的 keydown 事件。尝试通过 summernote 的初始配置为 keyDown 事件提供覆盖回调是可能的,但是非常丑陋并且由于 summernote 设置的预配置事件处理程序而有怪癖。

在 fiddle 中,我只使用了一个文本输入并为其指定了 ID richTextInput。另外,我删除了 onchange="onAnswerChoiceChange(this);",因为这会导致错误。

要在配置中提供覆盖,请使用:

$(optionEditors[i]).summernote({
  airMode: true,
  popover: {
    air: [
      ['font', ['bold', 'underline', 'clear']]
    ]
  },
  callbacks: {
    onKeydown: function(e) {
      if (e.keyCode === 32) { // catch "space"
        e.preventDefault();
        $('.note-editable>#richTextInput').val($('.note-editable>#richTextInput').val() + " ");
      }
    }
  }
});

note-editableclass是summernote初始化后创建的容器div。我们需要指定它,因为 summernote 在初始化之前自动复制 "rich-text-editor-to-be" 的所有内容,然后用 display:none 隐藏它们,所以仅仅尝试用 $('#richTextInput') 引用输入是行不通的,因为你会抓住隐藏的输入。

怪癖: 你会注意到,如果你尝试使用这段代码,summernote 会尝试自动将焦点提供给 actual rich文本编辑器 div 这是由于 summernote 注册的事件侦听器中提供的行为。你可以通过像这样提供超时来解决这个问题:

setTimeout(function() {
    $('.note-editable>#richTextInput').focus();
}, 1); 

正如我之前所说,这确实不是一个好的解决方案,虽然它可能会奏效,但我认为更好的方法是完全放弃文本输入,只初始化一个 div 或文本区域而不用正如图书馆所期望的那样嵌套在里面的任何东西。这样做会更容易,然后相应地设置它们的样式。使用 material 设计 styles/components 可能无法很好地协同工作,因为 material 需要输入或文本区域元素,而 summernote 将文本区域转换为 div,但这是一个不同的问题。

也许解决方案很简单。 <div contenteditable="true"> parent 已创建(也许您不需要 <input>),其中 RICH-EDITING 实际上发生了。

1) 飞行模式开启:https://jsfiddle.net/hwd5efe0/13/
2) 飞行模式关闭:https://jsfiddle.net/hwd5efe0/18/

(p.s。只改变了 JS )

另一种解决方案是使用 CSS 隐藏输入并使 summernote 看起来像一个表单控件:

for (var i=0; i<optionEditors.length; i++) {
    $(optionEditors[i]).summernote({
      airMode: true,
      popover: {
        air: [
          ['font', ['bold', 'underline', 'clear']]
        ]
      },
      callbacks: {
        onInit: function() {
               // make the editor like a "form-control"
               $('.note-editor').addClass('form-control');
               // Force editor height adding one space 
               $(this).summernote('code', ' ');
            }
        }      
    });

}

@查看工作示例https://jsfiddle.net/v8zhvsmo/