如何防止在 contenteditable 元素中按“Enter”后创建新的文本节点?

问题描述 投票:0回答:1

是否可以使用一些 CSS 属性 或HTML属性或JS解决方案 防止分割文本节点?

我不想在每次按“Enter”键后调用 div.normalize() 并且请不要建议使用textarea

🌀 我需要获取相对于文本开头的插入符号位置,但是当我按 Enter 时,浏览器每次都会创建一个新的文本节点,之后 Selection.anchorOffset 返回新创建的节点中的偏移量。但我想拥有唯一的一个文本节点并轻松获得插入符号位置

<!DOCTYPE html>Caret:<a id=Caret>0</a> Nodes:<a id=Nodes>1</a>
<div id=div contenteditable='plaintext-only'>Prevent Creating new textNodes</div>
<style>
  #Caret { color: red  }
  #Nodes { color: blue }
  div {
    padding: 10px;
    height: 5lh;
    outline: 1px solid;
    overflow-y:auto
  }
</style>
<script>  'use strict';
const S=getSelection();

div.onkeyup=div.onpointerup=()=>{
  Caret.text=S.anchorOffset
  Nodes.text=div.childNodes.length
}

div.focus()

</script>

我也不想手动处理“Enter”键 通过 event.preventDefault() 在 keydown 事件中

我正在寻找一个简单的解决方案

谢谢您!

javascript css contenteditable
1个回答
0
投票

此解决方案可能与您所说的非常狭窄的要求不完全匹配请不要建议使用textarea并且_而且我不想通过event.preventDefault()手动处理keydown事件中的“Enter”按下。

但你也说过:我正在寻找一个简单的解决方案,我看不到任何比这更简单的解决方案......

使用

pre
元素代替
div
,以便按原样处理换行符,并拦截
Enter
键击中,防止浏览器的默认行为,即添加新的子文本节点,而不是将新内容附加到独特的节点。

此解决方案将仅显示一个内容可编辑元素,其高度由其样式给出。如果您在其中输入新内容,即使添加新行,您也不会看到节点数增加。

'use strict';

//here I'm fetching the elements explicitely instead of using window scope
const div = document.getElementById('div');
const Caret = document.getElementById('Caret');
const Nodes = document.getElementById('Nodes');

div.addEventListener('keydown', function(event) {
  if (event.key === 'Enter') {

    //prevent the default behaviour (where the browser would add a new text node)
    event.preventDefault();

    //add a newline character at the caret position.
    const selection = window.getSelection();
    const caretPos = selection.anchorOffset;
    const textContent = div.textContent;

    //check if caret is at the end of the content..
    //this is needed because at the end of the content it requires a special behaviour for newline to show up and this condition will be checked when adding the \n
    const atEnd = caretPos === textContent.length;

    //replace the content adding a new line at the caret position
    const newTextContent =
      textContent.slice(0, caretPos)
      + '\n' + (atEnd ? '\n' : '') + textContent.slice(caretPos);
    div.textContent = newTextContent;

    //move the caret after the newline
    setCaretPosition(div, caretPos + 1);

    updateInfo();
  }
});

//move the caret at the new position
function setCaretPosition(elem, pos) {
  const textNode = elem.firstChild;
  const range = document.createRange();
  const sel = window.getSelection();
  range.setStart(textNode, pos);
  range.collapse(true);
  sel.removeAllRanges();
  sel.addRange(range);
}

function updateInfo() {
  setTimeout(() => {
    const selection = window.getSelection();
    Caret.textContent = selection.anchorOffset;
    Nodes.textContent = div.childNodes.length;
  }, 0);
}

div.addEventListener('keyup', updateInfo);
div.addEventListener('click', updateInfo);
div.addEventListener('input', updateInfo);

div.focus();
#Caret {
  color: red
}

#Nodes {
  color: blue
}

#div {
  padding: 10px;
   height: 5lh;
  outline: 1px solid;
  overflow-y: auto;  
}
<!DOCTYPE html>
Caret:<a id="Caret">0</a> Nodes:<a id="Nodes">1</a>
<pre id="div" contenteditable="true">Prevent Creating new textNodes</pre>

© www.soinside.com 2019 - 2024. All rights reserved.