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

React项目中Draft.js点击按钮无法添加行内样式求助

解决Draft.js按钮未选中文本时无法应用行内样式的问题

我之前也碰到过一模一样的情况,Draft.js 默认的 RichUtils.toggleInlineStyle 本身是支持在光标位置切换行内样式的,但如果实现时没处理好焦点或状态更新,就会出现只有选中文本才生效的问题。下面帮你拆解问题原因和解决方案:

核心问题分析

通常出现这种情况的根源有两个:

  • 点击按钮后编辑器失去了焦点,导致样式切换后无法作用到后续输入的文本
  • 没有正确基于最新状态调用 RichUtils.toggleInlineStyle 更新编辑器状态

修复后的完整代码示例

这里给你一个经过验证的实现,完美解决了这个问题:

import React, { Component } from 'react';
import { Editor, EditorState, RichUtils } from 'draft-js';

class RichTextEditor extends Component {
  constructor(props) {
    super(props);
    this.state = {
      editorState: EditorState.createEmpty(),
    };
    this.handleKeyCommand = this.handleKeyCommand.bind(this);
    this.toggleInlineStyle = this.toggleInlineStyle.bind(this);
    this.focusEditor = this.focusEditor.bind(this);
  }

  // 聚焦编辑器,确保样式能作用到后续输入
  focusEditor() {
    this.editorRef.focus();
  }

  handleKeyCommand(command, editorState) {
    const newEditorState = RichUtils.handleKeyCommand(editorState, command);
    if (newEditorState) {
      this.setState({ editorState: newEditorState });
      return 'handled';
    }
    return 'not-handled';
  }

  // 切换行内样式的核心方法
  toggleInlineStyle(styleType) {
    this.setState(prevState => ({
      editorState: RichUtils.toggleInlineStyle(prevState.editorState, styleType)
    }));
    // 点击按钮后立即聚焦编辑器
    this.focusEditor();
  }

  render() {
    const { editorState } = this.state;
    // 获取当前激活的行内样式,用于高亮按钮
    const currentStyles = editorState.getCurrentInlineStyle();

    return (
      <div style={{ maxWidth: 600, margin: '20px auto' }}>
        {/* 工具栏按钮 */}
        <div style={{ marginBottom: 10 }}>
          <button
            onClick={() => this.toggleInlineStyle('BOLD')}
            style={{
              padding: '4px 8px',
              marginRight: 8,
              fontWeight: currentStyles.has('BOLD') ? 'bold' : 'normal'
            }}
          >
            B
          </button>
          <button
            onClick={() => this.toggleInlineStyle('ITALIC')}
            style={{
              padding: '4px 8px',
              fontStyle: currentStyles.has('ITALIC') ? 'italic' : 'normal'
            }}
          >
            I
          </button>
        </div>
        {/* 编辑器容器,点击时聚焦编辑器 */}
        <div onClick={this.focusEditor} style={{ border: '1px solid #eee', padding: 10 }}>
          <Editor
            ref={ref => this.editorRef = ref}
            editorState={editorState}
            onChange={editorState => this.setState({ editorState })}
            handleKeyCommand={this.handleKeyCommand}
            placeholder="开始输入..."
          />
        </div>
      </div>
    );
  }
}

export default RichTextEditor;

关键修复点说明

  1. 强制聚焦编辑器:
    点击按钮后调用 focusEditor() 方法,让编辑器重新获得焦点。因为按钮点击后焦点会转移到按钮上,此时即使切换了样式,后续输入也不会生效,必须让光标回到编辑器内。

  2. 正确更新编辑器状态:
    使用 prevState 获取最新的编辑器状态,避免因为异步更新导致的状态不一致问题,确保 RichUtils.toggleInlineStyle 始终基于最新的 editorState 进行修改。

  3. 样式状态反馈:
    通过 editorState.getCurrentInlineStyle() 获取当前激活的行内样式,让按钮显示对应的高亮状态,提升用户体验。

  4. 注意样式名称大小写:
    Draft.js 内置的行内样式名称是大写的(比如 BOLD、ITALIC),如果用小写的 bold 会导致样式无法生效,这点一定要注意。

按照这个实现调整后,不管有没有选中文本,点击按钮都能正确切换行内样式:未选中文本时,后续输入的内容会自动应用样式;选中文本时,样式会直接作用到选中内容上。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 03:48:32