在添加跨度后如何在可编辑的内容中设置插入符位置;并将插入符号移动到跨度的末尾?

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

我有一个用于聊天应用程序的内容编辑器。当我标记用户时,我找到当前的 caretPosition 并向该位置添加一个跨度,如下所示;

<span class=\"highlight\" contenteditable=\"false\">${userName}</span> 

但是,当我用这个跨度替换标签时,我失去了可编辑内容的焦点,并且插入符号位置也丢失了。我尝试过查看这些答案,

答案1 答案2

但是在这两种情况下焦点都会丢失,如果我在 setCursorPosition 函数之前设置 el.focus() ,插入符号只会转到可编辑内容的开头。我的代码;

getCaretPositionInnerHTML() {
   var target = document.createTextNode("\u0001");
   document.getSelection().getRangeAt(0).insertNode(target);
   var position = this.contenteditable.nativeElement.innerHTML.indexOf("\u0001");
   target.parentNode.removeChild(target);
   return position;
}

saveMention(event, user): void { //lose focus after this
   event.stopPropagation();
   let tempString = this.contenteditable.nativeElement.innerHTML;
   let index = this.getCaretPositionInnerHTML();
   let replacement = this.getSpanFromUserFn(user);// returns the span in question
   let currentWordLength = this.getCurrentWord(tempString, index);// replace the current word with my span
   let newString = tempString.substring(0, index - currentWordLength.length) + replacement + tempString.substring(index + 1);
   this.contenteditable.nativeElement.innerHTML = newString;
}

ngOnChanges(changes: SimpleChanges) {
if (this.caretPosition) {
  console.log(changes);
  this.selection.removeAllRanges();
  let range = this.setCursorPosition(this.element.nativeElement, document.createRange(), {  pos: this.caretPosition, done: false});
  this.element.nativeElement.focus();
  range.collapse(true);
  this.sel.addRange(range);
}

//find the child node and relative position and set it on range
setCursorPosition(parent, range, stat) {
if (stat.done) return range;
if (parent.childNodes.length == 0) {
if (parent.textContent.length >= stat.pos) {
  range.setStart(parent, stat.pos);
  stat.done = true;
} else {
  stat.pos = stat.pos - parent.textContent.length;
}
} else {
for (var i = 0; i < parent.childNodes.length && !stat.done; i++) {
  this.currentNode = parent.childNodes[i];
  this.setCursorPosition(this.currentNode, range, stat);
}
}
return range;
}
javascript html angular dom
1个回答
0
投票

我碰巧遇到了一个用例,这就是我最终的结果:


  let cursorPosition;
  
  const getCursorLocation = (ele) => {
    var target = document.createTextNode("\u0001");
    document.getSelection().getRangeAt(0).insertNode(target);
    var position = ele.innerHTML.indexOf("\u0001");
    target.parentNode.removeChild(target);
    cursorPosition = position;
    console.log('position', position);
    return position;
  };
  
//find the child node and relative position and set it on range
  const findingRange = (ind, nodes, position) => {
    if (nodes[ind].textContent.length >= position) {
      if (nodes[ind].childNodes.length > 0) {
        return findingRange(0, nodes[ind].childNodes, position);
      }
      const node =
        nodes[ind].nodeName === "#text" ? nodes[ind] : nodes[ind].firstChild;
      return { node, offset: position };
    }
    return findingRange(
      ind + 1,
      nodes,
      position - nodes[ind].textContent.length
    );
  };
  
  const updateInput = (input) => {
    const userInputBox = document.getElementById("listening-input-change");
    if (userInputBox) {
      const currentText = userInputBox.innerHTML;
      const position = cursorPosition;
      const newText =
        currentText.substring(0, position) +
        input +
        currentText.substring(position);

      userInputBox.innerHTML = newText;

      const range = document.createRange(); //Create a range
      const sel = window.getSelection(); //get the selection object

      const startingNode = findingRange(
        0,
        userInputBox.childNodes,
        currentText.substring(0, position).replace(/<[^>]+>/g, "").length +
          input.length
      );
      range.setStart(startingNode.node, startingNode.offset);
      range.collapse(true);
      sel.removeAllRanges();
      sel.addRange(range);
      userInputBox.focus();

    }
  };
.listening-input-change {
  background: #fff;
  border: 1px solid #d4d6db;
  border-radius: 12px;
  color: #000;
  font-size: 14px;
  font-weight: 400;
  height: 100%;
  padding: 12px 12px 40px;
 }
<div
   contentEditable="true"
   id='listening-input-change'
   class="listening-input-change"></div>
<button onclick="updateInput('example text inserted')">set caret</button>
<script>
document.getElementById("listening-input-change").addEventListener("input", function () {
      const position = getCursorLocation(this);
});
</script>

  let cursorPosition;
  
  const getCursorLocation = (ele) => {
    var target = document.createTextNode("\u0001");
    document.getSelection().getRangeAt(0).insertNode(target);
    var position = ele.innerHTML.indexOf("\u0001");
    target.parentNode.removeChild(target);
    cursorPosition = position;
    console.log('position', position);
    return position;
  };
  
//find the child node and relative position and set it on range
  const findingRange = (ind, nodes, position) => {
    if (nodes[ind].textContent.length >= position) {
      if (nodes[ind].childNodes.length > 0) {
        return findingRange(0, nodes[ind].childNodes, position);
      }
      const node =
        nodes[ind].nodeName === "#text" ? nodes[ind] : nodes[ind].firstChild;
      return { node, offset: position };
    }
    return findingRange(
      ind + 1,
      nodes,
      position - nodes[ind].textContent.length
    );
  };
  
  const updateInput = (input) => {
    const userInputBox = document.getElementById("listening-input-change");
    if (userInputBox) {
      const currentText = userInputBox.innerHTML;
      const position = cursorPosition;
      const newText =
        currentText.substring(0, position) +
        input +
        currentText.substring(position);

      userInputBox.innerHTML = newText;

      const range = document.createRange(); //Create a range
      const sel = window.getSelection(); //get the selection object

      const startingNode = findingRange(
        0,
        userInputBox.childNodes,
        currentText.substring(0, position).replace(/<[^>]+>/g, "").length +
          input.length
      );
      range.setStart(startingNode.node, startingNode.offset);
      range.collapse(true);
      sel.removeAllRanges();
      sel.addRange(range);
      userInputBox.focus();

    }
  };
函数递归地查找范围的起始节点和偏移量。

然后在更新插入所需的文本后在 updateInput 内调用它。

.listening-input-change {
  background: #fff;
  border: 1px solid #d4d6db;
  border-radius: 12px;
  color: #000;
  font-size: 14px;
  font-weight: 400;
  height: 100%;
  padding: 12px 12px 40px;
 }
© www.soinside.com 2019 - 2024. All rights reserved.