做了一个 byd 编辑器插件,用户再也不汪汪叫了。。。

引言

大家好,我是程序员 K.N, 一个试图用代码和世界重新打结的前端小白~

先叠个甲,byd = ByteMD,小小的标题党一下,各位看官老爷轻喷。

前段时间,我们团队做了个面试刷题工具——面试鸭,而我也作为一名前端开发参与了该项目的开发。

在这个工具中,有一个流畅、简洁的 Markdown 编辑器,该编辑器所见即所得,支持代码高亮、代码块复制,标签解析、数学公式、流程图、对齐方式、图片自定义大小(仿语雀)、图片放大预览等功能。

今天,我将手把手带大家揭秘,这个 Markdown 编辑器是如何实现的,助你也能打造同款功能!


一、ByteMD 是啥?

其实这款编辑器是基于 ByteMD 实现的,它是字节开源的一款轻量编辑器,是使用 Svelte 构建的 Markdown 编辑器组件,它也可以用于其他框架,例如 React、Vue 和 Angular。

具有以下特性:

1)轻量级且与框架无关

2)易于扩展:ByteMD 有一个插件系统来扩展基本的 Markdown 语法,

3)默认安全:ByteMD 正确处理跨站点脚本(XSS) 攻击,例如 <script><img onerror>。无需引入额外的 DOM 清理步骤。

4)SSR 兼容:ByteMD 可以在服务器端渲染(SSR) 环境中使用,无需额外配置。

相关链接:

ByteMD 开源地址:https://github.com/pd4d10/bytemd

demo 示例:https://bytemd.js.org/playground/

二、快速集成 ByteMD

1、环境准备:

Node.js 16 及以上

2、基本使用

安装 ByteMD 相关依赖

npm install bytemd
npm instal @bytemd/react

安装 gfm(表格支持)插件、highlight 代码高亮插件

npm install @bytemd/plugin-gfm @bytemd/plugin-highlight

引入 ByteMD 汉化包

# 引入中文包
import zhHans from 'bytemd/locales/zh_Hans.json

用法

ByteMD 有两个组件:EditorViewer。Editor 是 Markdown 编辑器; View 通常用于显示呈现的 Markdown 结果,无需编辑。在使用组件之前,还要导入CSS文件以确保样式正确:

import 'bytemd/dist/index.css'

封装自定义的 Editor 和 Viewer 组件

接下来需要对官方的 Editor 和 Viewer 进行封装, 以提高组件的通用性。

新建 MdEditor 组件,示例写法如下:
import type { FC } from "react";
import { Editor } from "@bytemd/react";
import gfm from "@bytemd/plugin-gfm";
import gfmLocale from "@bytemd/plugin-gfm/locales/zh_Hans.json";
import highlight from "@bytemd/plugin-highlight";
import locale from "bytemd/locales/zh_Hans.json";
import "bytemd/dist/index.css";
import "./index.css";

interface Props {
  value?: string;
  onChange?: (v: string) => void;
  placeholder?: string;
}

const plugins = [
  gfm({
    locale: gfmLocale,
  }),
  highlight(),
];

/**
 * Markdown 编辑器
 */
const MdEditor: FC<Props> = (props) => {
  const { value = "", onChange, placeholder } = props;

  return (
    <div className="md-editor">
      <Editor
        value={value || ""}
        placeholder={placeholder}
        editorConfig={
  
  {
          // 不显示行数
          lineNumbers: false,
          autofocus: false,
        }}
        mode="split"
        locale={locale}
        plugins={plugins}
        onChange={onChange}
        />
    </div>
  );
};

export default MdEditor;

页面中使用
import "./App.css";
import MdEditor from "@/components/MdEditor";
import { useState } from "react";

function App() {
  const [value, setValue] = useState<string>("");

  return (
    <>
      <MdEditor value={value} onChange={setValue} />
    </>
  );
}

export default App;

这样,就能得到一个基本的编辑器了,大家可以在光标中输入看看有没有实现所见即所得呢?但是右上角多了一个 GitHub 的图标,咱们把它隐藏起来,主打的就是一个简洁~

/*隐藏 github 图标*/
.bytemd-toolbar-icon.bytemd-tippy.bytemd-tippy-right:last-child {
   
   
  display: none;
}

3、ByteMD 插件配置

安装插件

官方支持的插件已经有不少,但对于一款体验良好的编辑器来说,我觉得还不够,除了使用以下列表中的插件外,我们还需要拓展其他插件,且听我娓娓道来 ~

官方插件列表如下:

插件名 插件功能
@bytemd/plugin-breaks 默认md渲染时硬换行需要双空格或者双回车, 该插件确保正常回车即可硬换行
@bytemd/plugin-frontmatter 解析元数据
@bytemd/plugin-gemoji 解析gemoji表情
@bytemd/plugin-gfm 支持GFM(自动链接文字、删除、表格、任务列表)
@bytemd/plugin-highlight 代码高亮
@bytemd/plugin-highlight-ssr 代码高亮ssr版本
@bytemd/plugin-math 支持数学公式
@bytemd/plugin-math-ssr 支持数学公式ssr版本
@bytemd/plugin-medium-zoom 支持点击图片放大预览
@bytemd/plugin-mermaid 支持流程图

我们把几个常用的插件都安装上,在 plugins 中导入我们所需的插件:

import type { FC } from "react";
import { Editor } from "@bytemd/react";
import gfm from "@bytemd/plugin-gfm";
import gfmLocale from "@bytemd/plugin-gfm/locales/zh_Hans.json";
import gemoji from "@bytemd/plugin-gemoji";
import highlight from "@bytemd/plugin-highlight";
import math from "@bytemd/plugin-math";
import mathLocale from "@bytemd/plugin-math/locales/zh_Hans.json";
import mermaid from "@bytemd/plugin-mermaid";
import mermaidLocale from "@bytemd/plugin-mermaid/locales/zh_Hans.json";
import mediumZoom from "@bytemd/plugin-medium-zoom";
import locale from "bytemd/locales/zh_Hans.json";
import "bytemd/dist/index.css";
import "highlight.js/styles/vs.css";
import "github-markdown-css/github-markdown-light.css";
import "./index.css";

const plugins = [
  gfm({
    locale: gfmLocale,
  }),
  gemoji(),
  highlight(),
  math({
    locale: mathLocale,
  }),
  mermaid({
    locale: mermaidLocale,
  }),
  mediumZoom(),
];

自定义插件

ByteMD 使用 remark 和 rehype 生态系统来处理 Markdown. 完整流程如下:

  1. Markdown 文本被解析为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 进行用户定制的。官方文档中用了一个 plugin-math 插件作为例子解释了我们该如何编写插件,接下来,我带大家来自定义实现几个实用的插件,包括:居中插件、标签解析插件、代码块复制插件等。

添加对齐方式插件:

给输入的文本、图片、链接等进行对齐方式设置,实现原理就是通过给某个元素包裹上一个 p 标签,并通过 align 属性设置其在文本框内的位置。

代码如下:

1)给这三个对齐方式设置对应的 icon ,这里可以直接套用我的 svg。

export const ALIGN_CENTER = `
    <svg t="1719248469954" class="icon-symbol" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4377">
        <path d="M96 128h832v96H96zM96 576h832v96H96zM224 352h576v96H224zM224 800h576v96H224z" p-id="4378"></path>
    </svg>`;
export const ALIGN_LEFT = `
    <svg width="24" height="24" t="1719248152373" class="icon-symbol" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4230">
        <path d="M96 128h832v96H96zM96 576h832v96H96zM96 352h576v96H96zM96 800h576v96H96z" p-id="4231"></path>
    </svg>`;
export const ALIGN_RIGHT = `
    <svg t="1719248528798" class="icon-symbol" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4524">
        <path d="M96 128h832v96H96zM96 576h832v96H96zM352 352h576v96H352zM352 800h576v96H352z" p-id="4525"></path>
    </svg>`;

2)编写插件代码

import type {
   
    BytemdPlugin } from 'bytemd';
import zh_Hans from './localels/zh_Hans.json';
import {
   
    ALIGN_LEFT, ALIGN_CENTER, ALIGN_RIGHT } from './icon';

export interface AlignPluginOptions {
   
   
  locale?: Record<string, string>;
}

/**
 * 对齐方式插件
 */
export default function alignPlugin(options?: AlignPluginOptions): BytemdPlugin {
   
   
  const locale = {
   
    ...zh_Hans, ...options?.locale } as typeof zh_Hans;

  return {
   
   
    actions: [
      {
   
   
        title: locale.alignType,
        icon: ALIGN_CENTER,
        handler: {
   
   
          type
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值