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

Angular实现textarea文本加粗、斜体功能的问题求助

解决方案:Angular富文本编辑器(支持加粗/斜体及同时应用)

核心问题说明

原生<textarea>是纯文本控件,无法渲染HTML标签,所以你看到的是<strong>/<i>标签而非格式化后的文本。必须替换为contenteditable="true"的元素来实现富文本渲染,同时修复原逻辑中选中区域处理、状态判断的问题。


完整实现代码

1. HTML模板

<div class="formatting-buttons">
  <button class="bold-button" (click)="toggleFormat('bold')" [class.active]="isFormatActive('bold')">B</button>
  <button class="italic-button" (click)="toggleFormat('italic')" [class.active]="isFormatActive('italic')">I</button>
</div>
<div 
  class="editor" 
  contenteditable="true"
  (input)="onEditorInput($event)"
  #editor
></div>

2. TypeScript逻辑

import { Component, ViewChild, ElementRef } from '@angular/core';

@Component({
  selector: 'app-rich-text-editor',
  templateUrl: './rich-text-editor.component.html',
  styleUrls: ['./rich-text-editor.component.css']
})
export class RichTextEditorComponent {
  @ViewChild('editor') editor!: ElementRef<HTMLElement>;
  responseText: string = '';

  toggleFormat(format: 'bold' | 'italic') {
    const doc = this.editor.nativeElement.ownerDocument;
    const selection = doc.getSelection();
    if (!selection || selection.rangeCount === 0) return;

    const range = selection.getRangeAt(0);
    const parentElement = range.commonAncestorContainer as HTMLElement;
    const tagName = format === 'bold' ? 'STRONG' : 'I';
    const wrapperSelector = format === 'bold' ? 'strong' : 'i';

    // 判断选中区域是否已应用当前格式
    const isApplied = parentElement.tagName === tagName || parentElement.closest(wrapperSelector);

    if (isApplied) {
      // 移除格式:将标签内容提取并替换标签
      const wrapper = parentElement.closest(wrapperSelector);
      if (wrapper) {
        const parent = wrapper.parentNode;
        while (wrapper.firstChild) {
          parent?.insertBefore(wrapper.firstChild, wrapper);
        }
        parent?.removeChild(wrapper);
      }
    } else {
      // 应用格式:用对应标签包裹选中内容
      const wrapper = document.createElement(wrapperSelector);
      range.surroundContents(wrapper);
    }

    // 恢复选中状态
    selection.removeAllRanges();
    selection.addRange(range);
    // 同步编辑器内容到responseText
    this.responseText = this.editor.nativeElement.innerHTML;
  }

  // 判断当前选中区域是否激活了对应格式(用于按钮高亮)
  isFormatActive(format: 'bold' | 'italic'): boolean {
    const doc = this.editor.nativeElement.ownerDocument;
    const selection = doc.getSelection();
    if (!selection || selection.rangeCount === 0) return false;

    const parentElement = selection.getRangeAt(0).commonAncestorContainer as HTMLElement;
    const tagName = format === 'bold' ? 'STRONG' : 'I';
    const wrapperSelector = format === 'bold' ? 'strong' : 'i';

    return parentElement.tagName === tagName || parentElement.closest(wrapperSelector);
  }

  // 编辑器输入时同步内容
  onEditorInput(event: Event) {
    this.responseText = (event.target as HTMLElement).innerHTML;
  }
}

3. CSS样式(可选,优化编辑器外观)

.editor {
  border: 1px solid #ccc;
  padding: 8px;
  min-height: 100px;
  margin-top: 10px;
  font-family: inherit;
}

.formatting-buttons button {
  padding: 4px 8px;
  margin-right: 5px;
  border: 1px solid #ccc;
  background: #fff;
  cursor: pointer;
}

.formatting-buttons button.active {
  background-color: #e0e0e0;
}

.bold-button {
  font-weight: bold;
}

.italic-button {
  font-style: italic;
}

关键改进点

  • 替换textarea为contenteditable元素:实现HTML格式渲染,这是解决标签显示问题的核心
  • 精准操作选中区域:使用Range API处理选中内容的包裹/移除,避免原逻辑中全局replace导致的错误
  • 动态状态判断:根据选中区域的实际DOM结构判断格式是否已应用,支持局部文本的格式切换,而非全局状态
  • 支持格式嵌套:可同时对文本应用加粗和斜体(<strong><i>文本</i></strong>)
  • 实时内容同步:编辑器内容变化时自动更新responseText变量,保留原需求的数据绑定

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 07:38:14