803

0

ByteMD

ByteMD 是一个使用 Svelte 构建的 Markdown 编辑器组件。它也可以用于其他库/框架,例如 React、Vue 和 Angular。

ByteMD

测试

ByteMD 是一个使用 Svelte 构建的 Markdown 编辑器组件。它也可以用于其他库/框架,例如 React、Vue 和 Angular。

演示:https ://bytemd.js.org/playground/

特征

  1. 轻量级和框架无关 :ByteMD 是用Svelte构建的。它编译为 vanilla JS DOM 操作,无需导入任何 UI 框架运行时包,这使其轻量级,并易于适应其他库/框架。
  2. 易于扩展 :ByteMD 有一个插件系统来扩展基本的 Markdown 语法,这使得添加附加功能变得很容易,例如代码语法高亮、数学方程和美人鱼流程图。如果这些插件不能满足您的需求,您也可以编写自己的插件。
  3. 默认情况下是安全的 :ByteMD已经正确处理了跨站点脚本(XSS)攻击。无需引入额外的 DOM 清理步骤。<script>``<img onerror>
  4. SSR 兼容 :ByteMD 可以在服务器端渲染(SSR)环境中使用,无需额外配置。SSR 在某些情况下被广泛使用,因为它具有更好的 SEO 和在慢速网络连接中快速获取内容的时间。

安装

包裹 地位 描述
bytemd npm Svelte/Vanilla JS 组件
@bytemd/react npm react组件
@bytemd/vue npm Vue 2 组件
@bytemd/vue-next npm Vue 3 组件

旧版浏览器支持

NPM 包的默认入口只支持现代浏览器。要使旧版浏览器 ( IE9+ ) 工作,您可以使用 ESNext -> ES5 转译器编译它,例如BabelSWC

在 1.11.0 版本之后,ES5 捆绑包将不再可用。如果需要,可以使用1.11.0或更早的版本

请注意,polyfill 不包括在内,应手动导入,请参阅旧版浏览器示例

用法

有两个组件:EditorViewerEditor顾名思义,就是 Markdown 编辑器;Viewer通常用于显示渲染的 Markdown 结果而无需编辑。

在使用组件之前,请记住导入 CSS 文件以使样式正确:

import 'bytemd/dist/index.css'

Svelte

<script>
  import { Editor, Viewer } from 'bytemd'
  import gfm from '@bytemd/plugin-gfm'

  let value
  const plugins = [
    gfm(),
    // Add more plugins here
  ]

  function handleChange(e) {
    value = e.detail.value
  }
</script>

<template>
  <Editor {value} {plugins} on:change={handleChange} />
</template>

React

import { Editor, Viewer } from '@bytemd/react'
import gfm from '@bytemd/plugin-gfm'

const plugins = [
  gfm(),
  // Add more plugins here
]

const App = () => {
  const [value, setValue] = useState('')

  return (
    <Editor
      value={value}
      plugins={plugins}
      onChange={(v) => {
        setValue(v)
      }}
    />
  )
}

Vue

<template>
  <Editor :value="value" :plugins="plugins" @change="handleChange" />
</template>

<script>
import { Editor, Viewer } from '@bytemd/vue'
import gfm from '@bytemd/plugin-gfm'

const plugins = [
  gfm(),
  // Add more plugins here
]

export default {
  components: { Editor },
  data() {
    return { value: '', plugins }
  },
  methods: {
    handleChange(v) {
      this.value = v
    },
  },
}
</script>

### Vanilla JS

import { Editor, Viewer } from 'bytemd'
import gfm from '@bytemd/plugin-gfm'

const plugins = [
  gfm(),
  // Add more plugins here
]

const editor = new Editor({
  target: document.body, // DOM to render
  props: {
    value: '',
    plugins,
  },
})

editor.$on('change', (e) => {
  editor.$set({ value: e.detail.value })
})

选项

查看器

钥匙 类型 描述
value string(必需的) Markdown文本
plugins BytemdPlugin[] ByteMD 插件列表
sanitize (schema: Schema) => Schema 清理策略
remarkRehype 文件 remark-rehype 配置选项

编辑

Editor组件还接受 Viewer用于预览的选项。除此之外,还有其他一些选择:

钥匙 类型 描述
mode split, tab,auto 编辑器显示模式,默认:auto
previewDebounce number 预览的去抖时间(毫秒),默认值:300
placeholder string 编辑器占位符
editorConfig 文件 CodeMirror 编辑器配置
locale i18n 语言环境。可以在 找到可用的语言环境 bytemd/locales,默认值:使用 en.json
uploadImages function 指定如何上传图像。如果设置,图像图标将出现在工具栏上
maxLength number 值的最大长度(字符数)

Style定制

编辑

ByteMD Editor 的默认高度是 300px. 它可以被 CSS 覆盖:

.bytemd {
  height: calc(100vh - 200px);
}

其他样式也可以被覆盖,请参阅默认样式

查看器

查看器没有内置样式。您可以使用第三方 markdown 主题,例如juejin-markdown-themesgithub-markdown-css

插件系统

ByteMD 提供强大的插件系统进行定制。有几个官方插件支持代码语法高亮、数学方程和美人鱼流程图等功能。

如果您有更多自定义需求,您还可以编写自己的插件来支持它们。

官方插件

包裹 地位 描述
@bytemd/plugin-breaks npm 支持休息
@bytemd/plugin-frontmatter npm 解析frontmatter
@bytemd/plugin-gemoji npm 支持 Gemoji 简码
@bytemd/plugin-gfm npm 支持 GFM(自动链接文字、删除线、表格、任务列表)
@bytemd/plugin-highlight npm 突出显示代码块
@bytemd/plugin-highlight-ssr npm 高亮代码块(兼容 SSR)
@bytemd/插件数学 npm 支持数学公式
@bytemd/plugin-math-ssr npm 支持数学公式(兼容SSR)
@bytemd/plugin-medium-zoom npm 像中等缩放图像
@bytemd/插件Mermaid npm 支持Mermaid

技术概述

ByteMD 使用remarkrehype生态系统来处理 Markdown。完整的过程如下:

  1. 降价文本被解析为AST
  2. Markdown AST 可以被几个备注插件操作
  3. Markdown AST 转换为 HTML AST
  4. 出于安全原因对 HTML AST 进行了清理
  5. HTML AST 可以被几个rehype 插件操作
  6. HTML AST 被字符串化为 HTML
  7. 渲染 HTML 后的一些额外的 DOM 操作

也可以用流程图来描述:

插件系统

2,5,7 步骤是为通过 ByteMD 插件 API 进行用户定制而设计的。

创作插件

我们将以数学公式插件为例来引导您完成整个过程。

首先,根据 BytemdPlugin类型签名对项目进行脚手架:

import type { BytemdPlugin } from 'bytemd'

export default function mathPlugin(): BytemdPlugin {
  return {
    // to be implement
  }
}

然后我们更仔细地研究需求:如果我们想渲染像 $a+b$数学公式这样的语法,我们需要做几件事:

  • 支持 $a+b$语法作为 Markdown 中的数学公式(步骤 2)
  • 在 HTML 中正确呈现这些节点(步骤 5 或 7)
  • 此外,工具栏中的额外图标非常方便用户

首先,幸运的是,我们不需要自己实现它,因为remark-math已经做到了。我们唯一需要做的就是导入并使用它:

import type { BytemdPlugin } from 'bytemd'
+import remarkMath from 'remark-math'

export default function mathPlugin(): BytemdPlugin {
  return {
-    // to be implement
+    remark: (processor) => processor.use(remarkMath),
  }
}

然后考虑第二件事,会有点复杂,因为我们有两个选择,在第 5 步或第 7 步中做。不同的是第 5 步对 SSR 更友好,而第 7 步将渲染交给客户端. 这就是为什么我们有两个插件:@bytemd/plugin-math@bytemd/plugin-math-ssr

// if we choose step 5:
import type { BytemdPlugin } from 'bytemd'
import remarkMath from 'remark-math'
+import rehypeKatex from 'rehype-katex'

export default function mathPlugin(): BytemdPlugin {
  return {
    remark: (processor) => processor.use(remarkMath),
+   rehype: (processor) => processor.use(rehypeKatex),
  }
}

// if we choose step 7:
import type { BytemdPlugin } from 'bytemd'
import remarkMath from 'remark-math'
+import rehypeKatex from 'rehype-katex'

export default function mathPlugin(): BytemdPlugin {
  return {
    remark: (processor) => processor.use(remarkMath),
+   viewerEffect({ markdownBody }) {
+     const renderMath = async (selector: string, displayMode: boolean) => {
+       const katex = await import('katex').then((m) => m.default)
+
+       const els = markdownBody.querySelectorAll<HTMLElement>(selector)
+       els.forEach((el) => {
+         katex.render(el.innerText, el, { displayMode })
+       })
+     }
+
+     renderMath('.math.math-inline', false)
+     renderMath('.math.math-display', true)
+   },
  }
}

最后一件事是在工具栏上添加一个图标。我们使用 actionsprop 来实现它:

export default function mathPlugin(): BytemdPlugin {
  return {
    actions: [
      {
        title: 'Insert an math formula',
        icon: '', // 16x16 SVG icon
        handler: {
          type: 'action',
          click(ctx) {
            // to be implement:
            // the `ctx` is an instance of `BytemdEditorContext`, which has
            // several utility methods to help operate the CodeMirror editor state.

            // remember to call `focus` to avoid lost of focus
            editor.focus()
          },
        },
      },
    ],
  }
}

现在我们已经完成了一个极简版的插件!有关更多详细信息和参考,请查看源代码。

贡献者

执照

MIT