milkdown:所见即所得的markdown编辑器

·  阅读 850

官方文档:Milkdown

安装

{
  "dependencies": {
    "@material-design-icons/font": "^0.11.9",
    "@milkdown/core": "^6.4.1",
    "@milkdown/plugin-block": "^6.4.1",
    "@milkdown/plugin-clipboard": "^6.4.1",
    "@milkdown/plugin-cursor": "^6.4.1",
    "@milkdown/plugin-history": "^6.4.1",
    "@milkdown/plugin-indent": "^6.4.1",
    "@milkdown/plugin-listener": "^6.4.1",
    "@milkdown/plugin-math": "^6.4.1",
    "@milkdown/plugin-prism": "^6.4.1",
    "@milkdown/plugin-slash": "^6.4.1",
    "@milkdown/plugin-tooltip": "^6.4.1",
    "@milkdown/preset-gfm": "^6.4.1",
    "@milkdown/theme-nord": "^6.4.1",
    "@milkdown/utils": "^6.4.1",
    "katex": "^0.16.2",
    "prism-themes": "^1.9.0",
  }
}
复制代码
  • 若您希望在markdown中书写表格,请确保使用@milkdown/preset-gfm预设
  • milkdown中的图标使用了material-design-icon,请确保已经在项目中使用cdn引入图标库,或安装@material-design-icons/font包,并在项目中引入(import "@material-design-icons/font";
  • 代码高亮需要使用@milkdown/plugin-prism插件。prism主题需要额外引入。您可以安装prism-themes包,并在项目中引入其中一款主题(import "prism-themes/themes/prism-material-oceanic.min.css";

初始化

引入样式文件和图标库

import "@material-design-icons/font";
import "katex/dist/katex.min.css";
import "prism-themes/themes/prism-material-oceanic.min.css";
复制代码

创建编辑器实例

import {
  Editor,
  editorViewOptionsCtx,
  rootCtx,
} from "@milkdown/core";
import { block } from "@milkdown/plugin-block";
import { clipboard } from "@milkdown/plugin-clipboard";
import { cursor } from "@milkdown/plugin-cursor";
import { history } from "@milkdown/plugin-history";
import { indent } from "@milkdown/plugin-indent";
import { listener, listenerCtx } from "@milkdown/plugin-listener";
import { math } from "@milkdown/plugin-math";
import { prism } from "@milkdown/plugin-prism";
import { slash } from "@milkdown/plugin-slash";
import { tooltip } from "@milkdown/plugin-tooltip";
import { gfm } from "@milkdown/preset-gfm";
import { nord } from "@milkdown/theme-nord";

// 编辑器是否是只读的
let readonly = false;

// 编辑器实例
let editor: Editor | null = null;

/**
 * 创建编辑器实例
 */
const createEditor = async (data: {
  element: HTMLElement | null; // 编辑器渲染的DOM节点
  handleUpdate: (value: string) => void; // 编辑器内容更新时的回调
}) => {
  editor = await Editor.make()
    .use(nord)
    .use(tooltip)
    .use(history)
    .use(cursor)
    .use(clipboard)
    .use(block)
    .use(listener)
    .use(gfm)
    .use(prism)
    .use(slash)
    .use(indent)
    .use(math)
    .config((ctx) => {
      ctx.set(rootCtx, data.element);
      // 注册事件侦听器
      ctx.get(listenerCtx).markdownUpdated((_ctx, markdown) => {
        data.handleUpdate(markdown);
      });
      // 设置只读模式
      ctx.set(editorViewOptionsCtx, {
        editable: () => !readonly,
      });
    })
    .create();
  return editor;
};

复制代码

获取或设置编辑器内容

设置内容。

import { Editor } from "@milkdown/core";
import { replaceAll } from "@milkdown/utils";

let editor: Editor | null = null;

/**
 * 设置编辑器中的文本(全部替换)
 */
const setText = (text: string) => {
  editor?.action(replaceAll(text));
};
复制代码

获取编辑器内容建议通过事件侦听的方式。在初始化编辑器实例时添加markdownUpdated侦听器,随后每次编辑器内容变化时将触发回调函数。

切换只读模式

import { Editor } from "@milkdown/core";
import { forceUpdate } from "@milkdown/utils";

let readonly = false;
let editor: Editor | null = null;

/**
 * 设置编辑器的只读模式
 */
const setReadonly = (isReadonly: boolean) => {
  readonly = isReadonly;
  // 强制编辑器进行自我更新。在更新时将重新设置只读模式
  editor?.action(forceUpdate());
};
复制代码

获取目录

官方提供的获取大纲方法Milkdown | 宏无法获取到标题的DOM元素,且元素的id可能存在异常。您可以从DOM树中手动提取大纲。

export interface TitleListItem {
  // 标题级别
  level: number;
  // 标题文本
  text: string;
  // 标题dom节点(可以使用node.scrollIntoView())
  node: Element;
  id: number;
}

const getTitleList: () => TitleListItem[] = () => {
  let nodeList = document
    .querySelector(".milkdown .editor")
    ?.querySelectorAll("h1,h2,h3,h4,h5,h6");
  return Array.from(nodeList || []).map((node, index) => {
    return {
      level: parseInt(node.tagName.replace("H", "")),
      text: node.textContent || "",
      node,
      id: index,
    };
  });
};

复制代码

若希望编辑器滚动到某一条标题处,可以使用node.scrollIntoView()

分类:
前端
标签:
收藏成功!
已添加到「」, 点击更改