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

如何在Tiptap中将Node转换为Mark并支持前后输入文本

将Tiptap自定义Block Node转换为行内Mark的实现方案

要实现将原有的块级自定义Node转为可在行内前后输入文本的Mark,不需要大幅修改现有代码,只需要调整核心定义部分并适配Mark的特性,以下是具体实现:

修改后的完整代码

import { NodeViewWrapper } from "@tiptap/react";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import React from "react";
import { mergeAttributes, Mark } from "@tiptap/core";
import { ReactNodeViewRenderer } from "@tiptap/react";
import { faBook } from "@fortawesome/free-solid-svg-icons";

interface MyComponentProps {
  node: {
    attrs: {
      desc: string;
      url: string;
    };
  };
  updateAttributes: (attrs: Record<string, any>) => void;
  // Mark的NodeView需支持渲染包裹的内容
  content: React.ReactNode;
}

const StudyLinkMark: React.FC<MyComponentProps> = (props) => {
  const { desc, url } = props.node.attrs;

  return (
    // 改为行内布局容器,确保可与文本同行显示
    <NodeViewWrapper className="studylink-mark" style={{ display: "inline-flex", alignItems: "center", gap: "4px", margin: "0 4px" }}>
      <FontAwesomeIcon icon={faBook} />
      <a href={url} target="_blank" rel="noopener noreferrer">
        {desc}
      </a>
      {/* 若需要Mark包裹文本内容,取消注释下方代码 */}
      {/* {props.content} */}
    </NodeViewWrapper>
  );
};

export const studyLinkMark = Mark.create({
  name: "studyLinkMark",
  // 指定为行内元素组,支持在行内文本流中存在
  group: "inline",
  // 允许Mark包裹任意行内内容(无需包裹文本可设为"")
  content: "inline*",
  // 开启选中、拖拽特性
  selectable: true,
  draggable: true,

  addAttributes() {
    return {
      desc: {
        default: "Click here for more details",
      },
      url: {
        default: "https://example.com",
      },
    };
  },

  parseHTML() {
    return [
      {
        tag: "span.studylink-mark",
        getAttrs: (node) => {
          const el = node as HTMLElement;
          const linkEl = el.querySelector("a");
          return {
            desc: el.getAttribute("data-desc") || linkEl?.textContent,
            url: linkEl?.getAttribute("href")
          };
        },
      },
    ];
  },

  renderHTML({ HTMLAttributes }) {
    return [
      "span",
      mergeAttributes(HTMLAttributes, { class: "studylink-mark", "data-desc": this.attrs.desc }),
      ["i", { class: "fa-solid fa-book" }],
      ["a", { href: this.attrs.url, target: "_blank", rel: "noopener noreferrer" }, this.attrs.desc]
    ];
  },

  addNodeView() {
    return ReactNodeViewRenderer(StudyLinkMark);
  },

  // 添加命令用于插入/切换Mark
  addCommands() {
    return {
      setStudyLinkMark: (attrs) => ({ commands }) => {
        return commands.setMark(this.name, attrs);
      },
      toggleStudyLinkMark: (attrs) => ({ commands }) => {
        return commands.toggleMark(this.name, attrs);
      },
    };
  },
});

关键修改点说明

  1. 核心类型切换:将Node.create改为Mark.create,从块级节点转为行内标记类型
  2. 布局与分组调整:
    • group: "inline":指定Mark属于行内元素组,支持嵌入文本流
    • 容器样式改为inline-flex,确保与前后文本同行显示,实现可在两侧输入内容的效果
  3. HTML解析与渲染适配:
    • 改用span作为渲染根元素(行内元素),替代原块级自定义标签
    • 调整parseHTML逻辑,从行内元素中提取属性信息
  4. 命令补充:新增setStudyLinkMark和toggleStudyLinkMark命令,方便编辑器中调用插入或切换该Mark

使用建议

  • 在编辑器配置中注册该Mark:extensions: [studyLinkMark, ...]
  • 调用命令插入Mark:editor.commands.setStudyLinkMark({ desc: "学习资料", url: "https://your-url.com" })
  • 通过CSS自定义.studylink-mark的样式,确保与行内文本对齐协调

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 01:54:53