You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular中如何维护contenteditable div的显示文本与未格式化存储文本

解决方案

核心思路

全程维护两个独立数据:

  • 视图层:contenteditable里渲染带样式的@用户富文本,每个@用户的span节点绑定data-user-id自定义属性存储对应用户ID,避免重名冲突
  • 数据层:单独维护rawComment变量,每次视图内容变更时遍历DOM节点拼接出带##userId##标记的原始内容,直接用于后续存储

修改后的代码

HTML代码

<div id="commentInput"
    class='commentInput'
    placeholder="Add Comment..."       
    [mention]="users"
    [mentionConfig]="mentionConfig"
    contenteditable="true"
    (itemSelected)="itemSelected($event)"
    (input)="updateRawComment()">
</div>

TS代码

// 用于提交存储的原始带标记文本
rawComment: string = '';

mentionConfig = {
  labelKey:'fullName', 
  dropUp: true,
  allowSpace: true,
  mentionSelect: (e: any) => {
    return '##' + e.userId + '##';
  }
};

public htmlDoc: HTMLElement;
@Input() users: Users;

itemSelected(event: any) {
  const user = this.users.find(user => user.userId === event.userId);
  if (!user) return;

  setTimeout(() => {
    this.htmlDoc = document.getElementById('commentInput');
    // 替换时给span加自定义属性存userId
    this.htmlDoc.innerHTML = this.htmlDoc.innerHTML.replace(
      '##' + event.userId + '##',
      ` <span style="font-weight: bold; color: #0072f0" data-user-id="${event.userId}">@${user.fullName}</span>&nbsp;`
    );
    this.selectEnd();
    // 选中用户后同步更新原始文本
    this.updateRawComment();
  }, 10);
}

selectEnd() {
  const range = document.createRange();
  range.selectNodeContents(this.htmlDoc);
  range.collapse(false);
  const selection = window.getSelection();
  selection.removeAllRanges();
  selection.addRange(range);
}

// 核心方法:遍历DOM生成带标记的原始文本
updateRawComment() {
  this.htmlDoc = document.getElementById('commentInput');
  let rawContent = '';
  // 遍历所有子节点
  this.htmlDoc.childNodes.forEach(node => {
    // 普通文本节点直接取内容
    if (node.nodeType === Node.TEXT_NODE) {
      rawContent += node.textContent;
    } 
    // 是@用户的span节点,替换为##userId##格式
    else if (node.nodeType === Node.ELEMENT_NODE && node.tagName === 'SPAN' && node.dataset.userId) {
      rawContent += `##${node.dataset.userId}##`;
    }
    // 其他富文本节点可根据业务需求扩展处理逻辑
  });
  this.rawComment = rawContent.trim();
}

使用说明

提交评论时直接使用rawComment变量即可,该变量会实时同步输入框的所有内容,所有@用户都会自动替换为##userId##格式,不会受用户名重复影响。

内容的提问来源于stack exchange,提问作者Cody2099

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.23 16:54:02