Remirror项目深度解析:如何创建支持内容编辑的NodeView

Remirror项目深度解析:如何创建支持内容编辑的NodeView

remirror ProseMirror toolkit for React 🎉 remirror 项目地址: https://gitcode.com/gh_mirrors/re/remirror

前言

在现代富文本编辑器开发中,自定义节点(Custom Node)的实现是一个常见需求。Remirror作为基于ProseMirror的React富文本编辑器框架,提供了强大的NodeView机制来满足这一需求。本文将深入探讨如何在Remirror中创建支持内容编辑的自定义节点。

NodeView基础概念

NodeView是Remirror中的核心概念,它允许开发者在文档中插入自定义节点。简单来说,NodeView就是Remirror节点在DOM中的可视化表现。

举个例子,假设我们需要在编辑器中插入一个用户卡片,包含用户头像、姓名等信息,并且还希望在这个卡片内添加可编辑的评论区域。这种复杂需求就需要通过NodeView来实现。

两种实现NodeView的方式

Remirror提供了两种创建NodeView的方法:

  1. 底层方法:通过NodeViewsExtension手动创建NodeView,这种方式更灵活但复杂度较高
  2. 高级方法:使用ReactComponentExtension将React组件自动转换为NodeView,这是对React开发者更友好的方式

本文将重点介绍第二种方法,即如何使用React组件创建支持内容编辑的NodeView。

创建基础NodeView(无内容)

第一步:定义节点扩展

首先需要创建一个新的节点扩展,让Remirror认识我们的自定义节点。这里我们创建一个UserCardExtension

class UserCardExtension extends NodeExtension {
  get name() {
    return 'user-card' as const;
  }

  createNodeSpec(): NodeExtensionSpec {
    return {
      attrs: {
        id: { default: null },
        name: { default: '' },
        image: { default: '' },
      },
      content: '', // 不允许内容
      toDOM: (node) => {
        const attrs: DOMCompatibleAttributes = {
          'data-user-id': node.attrs.id,
          'data-user-name': node.attrs.name,
          'data-user-image': node.attrs.image,
        };
        return ['div', attrs];
      },
      parseDOM: [
        {
          attrs: {
            id: { default: null },
            name: { default: '' },
            image: { default: '' },
          },
          tag: 'div[data-user-id]',
          getAttrs: (dom) => {
            const node = dom as HTMLAnchorElement;
            return {
              id: node.getAttribute('data-user-id'),
              name: node.getAttribute('data-user-name'),
              image: node.getAttribute('data-user-image'),
            };
          },
        },
      ],
    };
  }
}

关键点说明:

  • name属性定义了节点的唯一标识
  • attrs定义了节点支持的属性
  • content: ''表示该节点不允许包含内容
  • toDOM定义了如何将节点渲染到DOM
  • parseDOM定义了如何从DOM解析回节点

第二步:创建React组件

接下来创建一个简单的React组件来表示用户卡片:

function UserCard({ node }) {
  const { name, imageSrc } = node.attrs;

  return (
    <div className='card'>
      <img src={imageSrc} />
      <h4>{name}</h4>
    </div>
  );
}

第三步:关联组件与扩展

最后将React组件关联到扩展:

class UserCardExtension extends NodeExtension {
  // ...其他代码
  ReactComponent: ComponentType<NodeViewComponentProps> = UserCard;
}

至此,我们已经创建了一个不支持内容编辑的基础NodeView。

进阶:支持内容编辑的NodeView

现在我们来升级这个NodeView,使其支持内容编辑功能。

修改节点规范

首先修改createNodeSpec方法:

createNodeSpec(): NodeExtensionSpec {
  return {
    attrs: {
      id: { default: null },
      name: { default: '' },
      imageSrc: { default: '' },
    },
    content: 'block*', // 允许空内容或块级内容
    toDOM: (node) => {
      const attrs: DOMCompatibleAttributes = {
        'data-user-id': node.attrs.id,
        'data-user-name': node.attrs.name,
        'data-user-image-url': node.attrs.imageSrc,
      };
      return ['div', attrs, 0]; // 注意这里的数字0
    },
    // ...其他代码
  };
}

关键变更:

  • content: 'block*'表示允许空内容或块级内容
  • toDOM返回值数组中添加了数字0,这是ProseMirror的特殊标记,表示内容插入位置

更新React组件

修改React组件以支持内容编辑:

function UserCard({ node, forwardRef }) {
  const { name, imageSrc } = node.attrs;

  return (
    <div className='card'>
      <div contentEditable='false'>
        <img src={imageSrc} alt='Avatar' style={{ width: '100%' }} />
        <h4>
          <b>{name}</b>
        </h4>
      </div>
      <p ref={forwardRef} />
    </div>
  );
}

关键点说明:

  • forwardRef必须附加到内容渲染的位置
  • 使用contentEditable='false'来禁用特定元素的编辑功能

技术原理深入

contentDOM机制

当NodeView需要包含可编辑内容时,Remirror使用contentDOM机制来管理这部分内容。forwardRef实际上就是contentDOM的挂载点。

内容位置标记

toDOM方法中返回的数组中的数字0(称为"hole")是一个特殊标记,它告诉ProseMirror在哪里插入子节点。这个标记必须是其父节点中的唯一子元素。

最佳实践

  1. 内容控制:对于不需要编辑的部分,记得添加contentEditable='false'
  2. 样式隔离:为自定义节点添加特定类名,避免样式污染
  3. 性能优化:复杂的NodeView应考虑使用React.memo进行优化
  4. 可访问性:确保自定义节点满足无障碍访问要求

总结

通过本文,我们学习了如何在Remirror中创建支持内容编辑的自定义NodeView。关键步骤包括:

  1. 创建节点扩展并定义其规范
  2. 开发对应的React组件
  3. 使用contentDOM机制支持内容编辑
  4. 合理控制节点的可编辑区域

这种机制非常灵活,可以用来实现各种复杂的编辑器功能,如嵌入式卡片、可编辑的代码块等。掌握NodeView的创建方法,可以大大扩展Remirror的编辑能力。

remirror ProseMirror toolkit for React 🎉 remirror 项目地址: https://gitcode.com/gh_mirrors/re/remirror

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

任彭安

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值