【问题标题】:Trying to wrap each word a user enters into a contenteditable="true" element in a div尝试将用户输入的每个单词包装到 div 中的 contenteditable="true" 元素中
【发布时间】:2021-09-13 22:31:01
【问题描述】:

我希望实现的行为将在用户键入消息时将用户键入的每个单词包装在

中。他们正在输入的父 div 具有 contenteditable="true"。

一个复杂的因素是,对于这个用例,一个“单词” div 可能包含两个单词(想象一个名称将被视为一个“单词”,因此例如

Bob Smith
可能会出现)。这意味着当用户按下空格键并将 (" ") 拆分为数组以构建 div.word DOM 元素时,我不能只获取所有 textContent。

我在想,当用户按下空格键时,我可以获取 contenteditable div 的所有子节点并循环遍历它们以检查哪个是 textNode,哪个不是(即,已经包含在 div.word 中的单词)。然后对于文本节点,我可以构建一个 div.word DOM 元素并将所有这些附加到 contenteditable div。

我希望这很清楚。这就是我所处的位置:

<div id="editor" contenteditable></div>
#editor {
  border: 1px solid #333;
  padding: 10px;
}

#editor .word {
  background: yellow;
  display: inline-block;
}
const editorElement = document.getElementById('editor');


function handleSpacebarPress() {
  // Get all editor child nodes
  let editorChildNodes = [...editor.childNodes];
  
  // Clear editor of all child nodes
  editor.innerHTML = '';
  
  editorChildNodes.forEach(node => {
    // If node is a text node (not a div.word element)
    if (node.nodeType === 3) {
      // Create div.word
      let wordDiv = document.createElement('div');
      wordDiv.className = 'word';
      wordDiv.textContent = node.textContent;
      
      editor.appendChild(wordDiv);
    } 
    // Else node is already a div.word element
    else {
        editor.appendChild(node);
    }
  });
  
  // Return caret to end of editor
  const editorLength = editor.childNodes.length;
  const lastNode = editor.childNodes[editorLength - 1]; // Last editor node
  
  const range = document.createRange();
  const selection = window.getSelection();
  
  range.setStart(lastNode, 1);
  range.collapse(true);
  selection.removeAllRanges();
  selection.addRange(range);
}


editorElement.addEventListener('keydown', e => {
  if (e.code === 'Space') {
    handleSpacebarPress();
  }
});

您可以在 jsfiddle here 上查看此内容。

现在似乎只是将所有单词直接放入一个 div.word 元素中,而我似乎无法为每个单词创建一个新元素。

有什么想法吗?

【问题讨论】:

  • 当您“将插入符号返回到编辑器末尾”时,光标将位于最后一个单词 div 内。在编辑器中最后生成的 div 之后放置一个空格,然后设置光标。否则,您正在对最后一个单词 div 进行内容编辑。
  • 我尝试添加 editor.appendChild(document.createTextNode(' '));就在“返回插入符号...”评论之前。这就是您在最后生成的 div 之后放置一个空格的意思吗?

标签: javascript


【解决方案1】:

我猜你想实现这样的目标: 请注意单词之间的空格如何没有突出显示,因此必须在主编辑器中。您可以通过在编辑器中的每个单词后添加空格并 trim()-ming 每个单词来解决此问题(正如您在 cmets 中指出的那样),这样内部节点的开头或结尾就没有空格。

您可能会重新考虑您的代码,因为它有一些缺点。

  • 基本上,您是在重新实现具有自定义语法突出显示功能的基本编辑器。
  • 如果您在编辑器的中间进行编辑,手动设置光标位置不起作用。
  • 复制和粘贴文本不会触发handleSpacebarPress

如果你想自己编写编辑器,我建议你使用一个函数highlightWords,它会在每个change 事件之后触发(可能会有一些人为延迟)。在该函数中,您可以使用正则表达式根据您的条件查找所有单词并将其替换为&lt;span class=word&gt;$1&lt;/span&gt;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-29
    相关资源
    最近更新 更多