如果两个相邻的可编辑范围和光标在中间,html 如何决定我写的是哪一个?

In case of two adjacent editable span and the cursor being in the middle, how html decide on which one i'm writing?

每次用户在输入文本中输入一个点时,我都会让这个脚本在可编辑的 div 中添加一个新的跨度,尝试根据是否存在分隔文本的点来分隔不同跨度中写入的文本. (我使用自定义标签 'mytag' 但它的行为实际上像一个跨度)

<div style="border:1px solid black;" id='editor-container' contenteditable="true"><mytag id="0">test</mytag></div>

JS:

var divContainer = document.getElementById("editor-container");
var nodeIdIncrement = 0;
var htmlBefore = divContainer.innerHTML; 
var html;
var editedCharIndex;

moveCursorOnDiv("0");

divContainer.addEventListener("input", function(e) {
    html=divContainer.innerHTML;

    editedCharIndex=findFirstDiffPos(htmlBefore,html);
    console.log("html[editedCharIndex]: "+html[editedCharIndex]);

    if(html[editedCharIndex]=="."){
        nodeIdIncrement++; 
      htmlBefore=html.substring(0, editedCharIndex+1)+'</mytag><mytag id="'+nodeIdIncrement+'">'+html.substring(editedCharIndex+1);

      divContainer.innerHTML = htmlBefore;
      moveCursorOnDiv(nodeIdIncrement);
    }else{
        htmlBefore = divContainer.innerHTML;
    }

}, false);

// Find index of newly added character making a diff between previuos situation and present one
function findFirstDiffPos(a, b) {
   var shorterLength = Math.min(a.length, b.length);

   for (var i = 0; i < shorterLength; i++){
       if (a[i] !== b[i]) return i;
   }

   if (a.length !== b.length) return shorterLength;

   return -1;
}

function moveCursorOnDiv(divId){
    console.log("divId: "+divId);
  var el = document.getElementById(divId);
  console.log("inner: "+el.innerHTML);
  var range = document.createRange();
  var sel = window.getSelection();
  range.setStart(el, 0);
  range.collapse(true);
  sel.removeAllRanges();
  sel.addRange(range);
}

这是JSFIDDLE

假设我在可编辑的 div "editor-container" 中输入一个字符 'A' 结果将是:

<div style="border:1px solid black;" id="editor-container" contenteditable="true">
   <mytag id="0">A</mytag>
</div>

然后我加一个点。结果将是:

<div style="border:1px solid black;" id="editor-container" contenteditable="true">
   <mytag id="0">A.</mytag>
   <mytag id="1"></mytag>
</div>

添加点后,我以编程方式(函数 moveCursorOnDiv)强制光标移动到新的 div。预期的结果是输入另一个字符 'B' 会导致情况:

<div style="border:1px solid black;" id="editor-container" contenteditable="true">
   <mytag id="0">A.</mytag>
   <mytag id="1">B</mytag>
</div>

相反,它实际上导致 Chrome 在:

<div style="border:1px solid black;" id="editor-container" contenteditable="true">
   <mytag id="0">A.B</mytag>
   <mytag id="1"></mytag>
</div>

虽然在 Firefox 中 90% 的时间都按预期运行,但有时会随机运行 Chrome。

那么,如果我的光标位于两个相邻的跨度之间,html 如何决定下一个输入是放在一个跨度中还是另一个跨度中? 有办法强制执行预期的行为吗?

编辑: 很明显,只有在以下 div 为空的情况下才会发生这种情况,因为存在歧义。如果您在下面的 div 中放置一个字符并将插入符号移动到位置“1”,它就像一个魅力。 (只是说这个问题不直接依赖于这个特定的代码,它在不同的条件下完美运行)

JSFIDDLE 2

这也意味着问题可以通过添加像 &nb sp; 这样的东西来解决。添加新的 div 时,但这不是一个干净的解决方案。

首先:您将 <div id="editor-container".....> </div> 设置为可编辑,因此当您键入 . 时,它会创建一个新的 <mytag> 和一个新的 Id 但它不会给出一个新 <mytag> 的可编辑选项,由于它不可编辑,鼠标指针保持在相同位置。

这里我做了一些修改:添加了一些边框和边距,使其可见

var divContainer = document.getElementById("editor-container");
var nodeIdIncrement = 0;
var htmlBefore = divContainer.innerHTML; 
var html;
var editedCharIndex;

moveCursorOnDiv("0");

divContainer.addEventListener("input", function(e) {
    html=divContainer.innerHTML;

    editedCharIndex=findFirstDiffPos(htmlBefore,html);
    console.log("html[editedCharIndex]: "+html[editedCharIndex]);

    if(html[editedCharIndex]=="."){
        nodeIdIncrement++; 
      htmlBefore=html.substring(0, editedCharIndex+1)+'</mytag><mytag id="'+nodeIdIncrement+'" contenteditable="true" style="margin: 10px;">'+html.substring(editedCharIndex+1);

      divContainer.innerHTML = htmlBefore;
      moveCursorOnDiv(nodeIdIncrement);
    }else{
        htmlBefore = divContainer.innerHTML;
    }

}, false);

// Find index of newly added character making a diff between previuos situation and present one
function findFirstDiffPos(a, b) {
   var shorterLength = Math.min(a.length, b.length);

   for (var i = 0; i < shorterLength; i++){
       if (a[i] !== b[i]) return i;
   }

   if (a.length !== b.length) return shorterLength;

   return -1;
}

function moveCursorOnDiv(divId){
    console.log("divId: "+divId);
  var el = document.getElementById(divId);
  console.log("inner: "+el.innerHTML);
  var range = document.createRange();
  var sel = window.getSelection();
  range.setStart(el, 0);
  range.collapse(true);
  sel.removeAllRanges();
  sel.addRange(range);
}
mytag {
  border: 1px solid black;
}
<div id='editor-container'>
    <mytag id="0" contenteditable="true">test</mytag>
</div>

在 JS 中进行了修改:

htmlBefore=html.substring(0, editedCharIndex+1)+'</mytag><mytag id="'+nodeIdIncrement+'" contenteditable="true" style="margin: 10px; border: 1px solid black;">'+html.substring(editedCharIndex+1);

您必须设置为可编辑,这样当您输入时,它会创建一个带有新 ID 的新对象,但不会为新对象提供可编辑选项,并且由于它不可编辑,因此鼠标指针保持在同一位置.

我所做的更改:添加了一些边框和边距,使其可见

var divContainer = document.getElementById("editor-container");
var nodeIdIncrement = 0;
var htmlBefore = divContainer.innerHTML;
var html;
var editedCharIndex;

moveCursorOnDiv("0");

divContainer.addEventListener("input", function(e) {
  html = divContainer.innerHTML;

  editedCharIndex = findFirstDiffPos(htmlBefore, html);
  console.log("html[editedCharIndex]: " + html[editedCharIndex]);

  if (html[editedCharIndex] == ".") {
    nodeIdIncrement++;
    htmlBefore = html.substring(0, editedCharIndex + 1) + '</mytag><mytag id="' + nodeIdIncrement + '" contenteditable="true" style="margin: 10px;">' + html.substring(editedCharIndex + 1);

    divContainer.innerHTML = htmlBefore;
    moveCursorOnDiv(nodeIdIncrement);
  } else {
    htmlBefore = divContainer.innerHTML;
  }

}, false);



<!-- begin snippet: js hide: false console: true babel: false -->
mytag {
  border: 1px solid black;
}

<div id='editor-container'>
    <mytag id="0" contenteditable="true">test</mytag>
</div>

function findFirstDiffPos(a, b) {
  var shorterLength = Math.min(a.length, b.length);

  for (var i = 0; i < shorterLength; i++) {
    if (a[i] !== b[i]) return i;
  }

  if (a.length !== b.length) return shorterLength;

  return -1;
}

function moveCursorOnDiv(divId) {
  console.log("divId: " + divId);
  var el = document.getElementById(divId);
  console.log("inner: " + el.innerHTML);
  var range = document.createRange();
  var sel = window.getSelection();
  range.setStart(el, 0);
  range.collapse(true);
  sel.removeAllRanges();
  sel.addRange(range);
}