在 React 中使用 TipTap 构建富文本编辑器(附带提及)

如果您想使用功能强大、可自定义的 RichText 编辑器增强您的 React 应用,TipTap 是一个绝佳的选择。本教程将指导您将 TipTap 集成到您的项目中并添加提及功能以获得动态用户体验。

您将构建什么

在本教程结束时,您将获得:

  • 使用 TipTap 构建的功能齐全的 RichText 编辑器。
  • 支持由@触发的提及,并附带动态建议列表。
  • 深入了解解决诸如占位符可见性和光标保存等边缘情况。
  • 有关 TipTap 的更多信息,请访问官方文档或浏览其 GitHub 存储库。

    步骤 1:安装依赖项

    在深入研究之前,请安装所需的库:

    npm install @tiptap/react @tiptap/starter-kit @tiptap/extension-mention

    步骤 2:创建一个基本的富文本编辑器

    首先创建一个 RichTextEditor 组件。以下是一个简单的实现:

    import { useEditor, EditorContent } from '@tiptap/react';  
    
    import StarterKit from '@tiptap/starter-kit';  
    
    export const RichTextEditor = ({ content, onChange }) => {  
      const editor = useEditor({  
        extensions: [StarterKit],  
        content: content,  
        onUpdate: ({ editor }) => {  
          onChange(editor.getHTML());  
        },  
      });  
      return ;  
    };

    步骤 3:添加提及

    提及可增强用户交互性,尤其是在聊天或协作应用程序中。要实现它们:

  • 安装并配置提及扩展
  • 修改 RichTextEditor 组件以包含 Mention 扩展:

    import Mention from '@tiptap/extension-mention';  
    
    export const RichTextEditor = ({ content, onChange, mentions }) => {  
      const editor = useEditor({  
        extensions: [  
          StarterKit,  
          Mention.configure({  
            HTMLAttributes: { class: 'mention' },  
            suggestion: {  
              items: ({ query }) =>  
                mentions.filter(item => item.display.toLowerCase().includes(query.toLowerCase())).slice(0, 5),  
              render: () => {  
                let component;  
                let popup;  
                return {  
                  onStart: (props) => {  
                    popup = document.createElement('div');  
                    popup.className = 'mention-popup';  
                    document.body.appendChild(popup);  
                    component = {  
                      updateProps: () => {  
                        popup.innerHTML = `  
                          
    ${props.items.map(item => ` `).join('')}
    `; }, destroy: () => popup.remove(), }; popup.addEventListener('click', (e) => { const button = e.target.closest('button'); if (button) { const index = Array.from(popup.querySelectorAll('.item')).indexOf(button); props.command({ id: props.items[index].id, label: props.items[index].display }); } }); component.updateProps(); }, onExit: () => component?.destroy(), }; }, }, }), ], content, onUpdate: ({ editor }) => onChange(editor.getHTML()), }); return ; };

    步骤 4:设置提及弹出窗口的样式

    提及应在视觉上有所区别。添加以下样式以增强可用性:

    .mention-popup {  
      background: white;  
      border-radius: 8px;  
      box-shadow: 0px 2px 8px rgba(0, 0, 0, 0.1);  
      padding: 8px;  
      position: absolute;  
      z-index: 1000;  
    }  
    .mention-popup .items {  
      display: flex;  
      flex-direction: column;  
    }  
    .mention-popup .item {  
      padding: 8px;  
      cursor: pointer;  
      border-radius: 4px;  
    }  
    
    .mention-popup .item:hover,  
    .mention-popup .item.is-selected {  
      background: #f0f0f0;  
    }

    步骤 5:实施过程中遇到的极端情况

  • 光标跳跃:为避免打字时光标跳跃,请确保内容更新保留光标的位置:
  • const editor = useEditor({  
      extensions: [StarterKit],  
      content,  
      onUpdate: ({ editor }) => {  
        const selection = editor.state.selection;  
        onChange(editor.getHTML());  
        editor.commands.setTextSelection(selection);  
      },  
    });
  • 占位符不可见:
  • 使用 Placeholder 扩展在编辑器为空时显示提示:

    import Placeholder from '@tiptap/extension-placeholder';  
    const editor = useEditor({  
      extensions: [  
        StarterKit,  
        Placeholder.configure({ placeholder: 'Type something...' }),  
      ],  
    });
  • 提及建议未显示:检查 suggestions.items 方法以确保它过滤并返回预期列表。
  • 步骤 6:集成到您的应用中

    将编辑器包装在模态或表单组件中,使其成为更大功能(例如通知或评论)的一部分。以下是示例:

    import React from 'react';  
    
    const NotificationForm = ({ mentions, onSubmit }) => {  
      const [content, setContent] = React.useState('');  
      return (  
        
    onSubmit(content)}> ); };

    结论

    使用 TipTap,您可以构建功能强大且用户友好的 RichText 编辑器。添加提及可增强应用的互动性,让用户更感兴趣。