如何在React版Tiptap编辑器中添加{{first name}}变量?
在React Tiptap中实现带自定义样式的{{变量}}功能
不用纠结mention插件,直接自定义一个Inline节点扩展就能实现需求,以下是具体步骤:
1. 创建自定义变量节点扩展
创建一个Variable扩展,继承Tiptap的Node类,定义变量的结构、解析规则和渲染方式:
import { Node } from '@tiptap/core'; import { ReactNodeViewRenderer } from '@tiptap/react'; import VariableComponent from './VariableComponent'; export const Variable = Node.create({ name: 'variable', inline: true, group: 'inline', selectable: true, draggable: true, addAttributes() { return { name: { default: '', parseHTML: element => element.getAttribute('data-name'), renderHTML: attributes => ({ 'data-name': attributes.name }), }, }; }, parseHTML() { return [ { tag: 'span.variable', }, ]; }, renderHTML({ node }) { return ['span', { class: 'variable', 'data-name': node.attrs.name }, `{{${node.attrs.name}}}`]; }, addNodeView() { return ReactNodeViewRenderer(VariableComponent); }, });
2. 编写变量渲染的React组件
创建VariableComponent.jsx,自定义变量的UI样式,完全匹配你需要的效果:
import React from 'react'; import { NodeViewWrapper } from '@tiptap/react'; const VariableComponent = ({ node, selected }) => { return ( <NodeViewWrapper className={`variable ${selected ? 'selected' : ''}`}> <span className="variable__text">{{{node.attrs.name}}}</span> </NodeViewWrapper> ); }; export default VariableComponent;
3. 添加样式
在CSS文件里定义变量的外观,比如:
.variable { background-color: #e8f0fe; border-radius: 4px; padding: 2px 6px; margin: 0 2px; font-family: monospace; color: #165dff; cursor: pointer; } .variable.selected { outline: 2px solid #165dff; }
4. 配置并初始化编辑器
在你的React组件中引入自定义扩展,初始化Tiptap编辑器:
import { useEditor, EditorContent } from '@tiptap/react'; import StarterKit from '@tiptap/starter-kit'; import { Variable } from './Variable'; const Editor = () => { const editor = useEditor({ extensions: [ StarterKit, Variable, ], content: '<p>Hello <span class="variable" data-name="first name">{{first name}}</span>!</p>', }); // 定义插入变量的函数 const insertVariable = (name) => { if (!editor) return; editor.chain().focus().insertContent(`<span class="variable" data-name="${name}">{{${name}}}</span>`).run(); }; return ( <div> <button onClick={() => insertVariable('first name')}>插入{{first name}}</button> <button onClick={() => insertVariable('last name')}>插入{{last name}}</button> <EditorContent editor={editor} /> </div> ); }; export default Editor;
额外优化:输入触发提示(可选)
如果需要输入{{时弹出变量选择菜单,可以结合@tiptap/suggestion插件实现,核心是定义触发规则和菜单组件:
import { Suggestion } from '@tiptap/suggestion'; import { Variable } from './Variable'; // 配置suggestion const variableSuggestion = { items: ({ query }) => { const variables = ['first name', 'last name', 'email', 'phone']; return variables.filter(item => item.toLowerCase().includes(query.toLowerCase())); }, render: () => { // 自定义菜单渲染逻辑,比如下拉列表 // 具体实现可以参考Tiptap官方suggestion示例 }, command: ({ editor, range, props }) => { editor .chain() .focus() .deleteRange(range) .insertContentAt(range, `<span class="variable" data-name="${props.item}">{{${props.item}}}</span>`) .run(); }, allow: ({ state, range }) => { const $from = state.doc.resolve(range.from); return $from.parent.type.name === 'paragraph'; }, }; // 在Variable扩展中添加suggestion export const Variable = Node.create({ // ... 其他配置 addProseMirrorPlugins() { return [ Suggestion({ editor: this.editor, ...variableSuggestion, trigger: '{{', // 触发字符 }), ]; }, });
这样就能完全实现你需要的{{变量}}功能,包括自定义UI样式,比用mention插件更贴合需求。
内容的提问来源于stack exchange,提问作者Azim Uddin Ahamed
相关产品推荐
相关产品推荐

