一款功能强大的markdown编辑器tui.editor使用示例详解

目录
  • 简介
  • 安装使用
    • 安装
    • 初始化
    • 官方插件
    • 功能拓展
  • 实现源码

简介

最近在捯饬自己的个人网站,想找一款类似于掘金的markdown编辑器,主要诉求包含实时预览、语法高亮、自动生成目录索引。对比了市面上主流的几款编辑器,最后采用了@toast-ui/editor。选择的主要原因就是开箱即用,内置一些实用的插件,如表格并且支持合并单元格、语法高亮、图形展示、uml绘制等;支持自定义插件扩展,因为这款编辑器是基于prosemirror,前身即codemirror,编辑器本身是偏底层的,提供了丰富的api供我们自定义开发,这也大大增强了编辑器的灵活性,如果想加一个目录索引,我们完全可以自定义开发一个插件使用。

在初次使用过程中,也遇到一些注意点,本文以vue3为例,简单介绍@toast-ui/editor的使用过程。

安装使用

安装

npm install @toast-ui/editor -S

初始化

import Editor from '@toast-ui/editor'
import '@toast-ui/editor/dist/toastui-editor.css'
import '@toast-ui/editor/dist/i18n/zh-cn';
export default {
    mounted () {
      const editor = new Editor({
        el: this.$refs.editor,
        language: 'zh-CN',
        initialEditType: 'markdown',
        previewStyle: 'vertical',
      });
    }
  }

通过以上两步,我们就能得到一个简易的编辑器了,如下图所示:

显然我们的目的不仅如此,markdown编辑器还缺少语法高亮、目录栏,接下来我们看下如何扩展tui

官方插件

官方内置了以下插件:

插件名称 用途
@toast-ui/editor-plugin-chart 图形渲染
@toast-ui/editor-plugin-code-syntax-highlight 语法高亮
@toast-ui/editor-plugin-color-syntax 文本添加颜色
@toast-ui/editor-plugin-table-merged-cell 合并单元格
@toast-ui/editor-plugin-uml 渲染UML

接下来我们配置代码语法高亮。

  • 安装插件
npm install @toast-ui/editor-plugin-code-syntax-highlight
  • 使用
import 'prismjs/themes/prism.css';
import '@toast-ui/editor-plugin-code-syntax-highlight/dist/toastui-editor-plugin-code-syntax-highlight.css';
import Editor from '@toast-ui/editor';
// 支持所有语言语法高亮
import codeSyntaxHighlight from '@toast-ui/editor-plugin-code-syntax-highlight/dist/toastui-editor-plugin-code-syntax-highlight-all.js';
const editor = new Editor({
  // ...
  plugins: [codeSyntaxHighlight]
});

功能拓展

目前编辑器包含了语法高亮,如果需要添加目录索引,可以监听文档编辑的change事件,获取markdown文档内容,通过正则表达式解析即可。具体实现如下:

const editor = new Editor({
  // ...
  events: {
    change: this.handleContentChange.bind(this)
  },
});
methods: {
  handleContentChange () {
    const mdText = this.editor.mdEditor.getMarkdown()
    this.parseMdTitle(mdText)
  },
  parseMdTitle (mdText) { // 解析markdown title
    const pattern = /^(#+)\s+(.+)/mg
    let result = mdText.match(pattern)
    if (!result) return
    const catalogList = result.map((vv, index) => {
      const levelText = vv.match(/^(#+)/)
      return {
        level: levelText[0].length, // 目录级别
        index,
        cls: `heading-${levelText[0].length}`,
        content: vv.slice(levelText[0].length).trim(), // 内容
      }
    })
    this.catalogList = catalogList
  }
}

以上仅仅是一些基础的使用。markdown基础语法无法满足我们需要时、需要手动修改渲染样式等需求,tui.editor也提供相应的能力。如需要修改标题的默认渲染样式,我们可以使用customHTMLRenderer,这一块官方文档较少,可以从源码看出默认书写规则,内置schema位置详见源码libs\toastmark\src\html\baseConvertors.ts

new Editor({
  // ...
  customHTMLRenderer: {
    heading (node, { entering }) {
      const spec = {
        type: entering ? 'openTag' : 'closeTag',
        tagName: `h${node.level}`,
        outerNewLine: true,
      };
      // 给每个header添加class
      if (entering) spec.attributes = {
        'class': `heading${node.level}`
      }
      return spec
    }
  }
})

最新3.0版本的编辑器是基于Prosemirror,有兴趣的小伙伴可以去看下,功能十分强大,也是level1级富文本编辑器的典型代表。

编辑器最终效果图如下:

实现源码

<template>
  <div class="full">
    <div class="markdown-editor" ref="editor"></div>
    <div class="catalog-container" v-if="catalogList.length > 0">
      <div class="catalog-title">目录</div>
      <template v-for="(item, index) in catalogList" :key="index">
        <div class="catalog-item" :class="item.cls">
          <a :href="'#heading' + (index + 1)" rel="external nofollow" >{{item.content}}</a>
        </div>
      </template>
    </div>
  </div>
</template>
<script>
  import Editor from '@toast-ui/editor'
  import '@toast-ui/editor/dist/toastui-editor.css'
  import '@toast-ui/editor/dist/i18n/zh-cn';
  import 'prismjs/themes/prism.css';
  import '@toast-ui/editor-plugin-code-syntax-highlight/dist/toastui-editor-plugin-code-syntax-highlight.css';
  import codeSyntaxHighlight from '@toast-ui/editor-plugin-code-syntax-highlight/dist/toastui-editor-plugin-code-syntax-highlight-all.js';
  import '@toast-ui/editor-plugin-table-merged-cell/dist/toastui-editor-plugin-table-merged-cell.css';
  import tableMergedCell from '@toast-ui/editor-plugin-table-merged-cell';
  export default {
    data () {
      return {
        catalogList: []
      }
    },
    mounted () {
      this.editor = new Editor({
        el: this.$refs.editor,
        language: 'zh-CN',
        initialEditType: 'markdown',
        previewStyle: 'vertical',
        placeholder: '请输入内容',
        plugins: [codeSyntaxHighlight, tableMergedCell],
        events: {
          change: this.handleContentChange.bind(this)
        },
        customHTMLRenderer: {
          heading (node, { entering }) {
            const spec = {
              type: entering ? 'openTag' : 'closeTag',
              tagName: `h${node.level}`,
              outerNewLine: true,
            };
            // 添加自定义属性
            if (entering) spec.attributes = {
              'class': `heading${node.level}`
            }
            return spec
          }
        }
      })
    },
    methods: {
      handleContentChange () {
        const mdText = this.editor.mdEditor.getMarkdown()
        this.parseMdTitle(mdText)
      },
      parseMdTitle (mdText) { // 解析markdown title
        const pattern = /^(#+)\s+(.+)/mg
        let result = mdText.match(pattern)
        if (!result) return
        const catalogList = result.map((vv, index) => {
          const levelText = vv.match(/^(#+)/)
          return {
            level: levelText[0].length, // 目录级别
            index,
            cls: `heading-${levelText[0].length}`,
            content: vv.slice(levelText[0].length).trim(), // 内容
          }
        })
        this.catalogList = catalogList
      }
    }
  }
</script>
<style scoped>
  .full {
    position: relative
  }
  .catalog-container {
    box-sizing: border-box;
    position: absolute;
    right: 0;
    bottom: 32px;
    width: 200px;
    height: 300px;
    padding: 16px 0;
    background-color: rgba(255, 255, 255, .65);
    border: 1px solid #ccc;
    border-radius: 4px;
  }
  .catalog-title {
    text-align: center;
    padding-bottom: 12px;
  }
  .catalog-item {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    padding: 4px 8px;
    font-size: 14px;
    user-select: none;
  }
  .catalog-item a {
    color: rgba(0, 0, 0, .65);
    text-decoration: none;
  }
  .heading-2 {
    padding-left: 24px;
  }
  .heading-3 {
    padding-left: 48px;
  }
  .catalog-item a:hover {
    color: cadetblue;
  }
  .markdown-editor {
    height: 100% !important;
    background: #fff;
    border-radius: 4px;
  }
</style>

参考资料

以上就是一款功能强大的markdown编辑器tui.editor使用示例详解的详细内容,更多关于markdown编辑器tui.editor的资料请关注我们其它相关文章!

(0)

相关推荐

  • 如何在在Vue3中使用markdown 编辑器组件

    目录 安装 引入组件 基础用法 保存后的 markdown 或者 html 文本如何渲染在页面上? 安装 # 使用 npm npm i @kangc/v-md-editor@next -S # 使用yarn yarn add @kangc/v-md-editor@next 引入组件 import { creatApp } from 'vue'; import VMdEditor from '@kangc/v-md-editor'; import '@kangc/v-md-editor/lib/s

  • 分享一个基于Ace的Markdown编辑器

    我认为的编辑器分成两类,一种是分为左右两边实现即时渲染:一种是先写语法,然后通过按钮实现渲染. 其实即时渲染也不难,共同需要考虑的问题就是xss,因为渲染库能自定义第三方的xss过滤(之前是通过设置来实现,也就是本身自带,不过在某个版本后被取消了),所以xss就用官方推荐的dompurify.即时渲染可以通过编辑器本身api实现文本变动监听来实现,还有一个需要考虑的问题就是代码与渲染区域的对应.但因为这与我的需求相悖,在这里就不介绍了,相信小老板们都能轻松实现 统一惯例,我们来看看效果图 上面的

  • JavaScript markdown 编辑器实现双屏同步滚动

    目录 前言 百分比滚动 双屏同时渲染占用面积大的元素 赋上一个索引 踩坑 前言 由于一直在使用 markdown 编辑器写技术文章,所以对于编写体验很敏感.我发现各大社区的 markdown 编辑器基本都有同步滚动功能.只不过有些做得好,有些做得马马虎虎.出于好奇,我就打算自己亲自实现一下这个功能. 思考了一段时间,最后想出来了三种方案: 百分比滚动 双屏同时渲染占用面积大的元素 每一行的元素都赋上一个索引,根据索引来精确同步每一行的滚动高度 百分比滚动 假设现在正在滚动 a 屏,那 a 屏的滚

  • Vue如何整合mavon-editor编辑器(markdown编辑和预览)

    目录 简介 说明 官网网址 使用编辑功能 代码 使用预览功能 结果展示 简介 说明 本文介绍Vue如何使用markdown编辑器. mavon-editor是目前比较主流的markdown编辑器,本文介绍它的使用方法. 官网网址 https://github.com/hinesboy/mavonEditor 安装mavon-editor依赖 npm install mavon-editor -P 注册mavon-editor编辑器 在main.js中加入如下内容: import mavonEdi

  • 一个HTML标签教你实现带动画的抖音LOGO效果

    目录 大家好,我是零一,今天给大家表演 仅用一个HTML标签实现带动画的抖音LOGO,涉及了很多知识点,欢迎交流讨论 先上结果,最终实现效果如下: 还原度应该还可以吧? 抖音Logo结构 想要用CSS来画抖音的Logo,前提要先了解它的构造,一定是一些几何图形的拼接组合,因为之前很多业界大佬已经扒过抖音的Logo的结构了,我就拿来借用一下: 好的,有点复杂,简化一下,其实就是 4 个部分 每个颜色划出来的区域代表一个部分,所以最后是:1/4圆环 + 半圆 + 长条矩形 + 半径略大一些的1/4圆

  • 一款功能强大的markdown编辑器tui.editor使用示例详解

    目录 简介 安装使用 安装 初始化 官方插件 功能拓展 实现源码 简介 最近在捯饬自己的个人网站,想找一款类似于掘金的markdown编辑器,主要诉求包含实时预览.语法高亮.自动生成目录索引.对比了市面上主流的几款编辑器,最后采用了@toast-ui/editor.选择的主要原因就是开箱即用,内置一些实用的插件,如表格并且支持合并单元格.语法高亮.图形展示.uml绘制等:支持自定义插件扩展,因为这款编辑器是基于prosemirror,前身即codemirror,编辑器本身是偏底层的,提供了丰富的

  • 更强大的React 状态管理库Zustand使用详解

    目录 介绍 创建项目项目 安装项目依赖 创建项目结构 设置环境变量 服务 设置 store 清除/重置存储 介绍 在这篇文章中,我会介绍 Zustand 在实际项目中的使用. 我会构建一个 GitHub 用户搜索项目,在项目中通过调用 GitHub API 来实现搜索用户的功能.我还会并演示如何直接从 Zustand 存储中进行 API 调用,并将状态持久化到 sessionStorage 或 localStorage 中. 完成效果如下: 创建项目项目 首先,我们需要创建一个新的 React

  • JavaScript中的ajax功能的概念和示例详解

    AJAX即"Asynchronous Javascript And XML"(异步JavaScript和XML). 个人理解:ajax就是无刷新提交,然后得到返回内容. 对应的不使用ajax时的传统网页如果需要更新内容(或用php做处理时),必须重载整个网页页面. 示例: html代码如下 <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>

  • Java实现图片裁剪功能的示例详解

    目录 前言 Maven依赖 代码 验证一下 前言 本文提供将图片按照自定义尺寸进行裁剪的Java工具类,一如既往的实用主义. Maven依赖 <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>30.1.1-jre</version> </dependency> <dependen

  • Ajax实现上传图像功能的示例详解

    最终效果展示 xhr发起请求 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="widt

  • go语言定时器Timer及Ticker的功能使用示例详解

    目录 定时器1-"*/5 * * * * *" 设置说明 定时器2-Timer-Ticker Timer-只执行一次 Ticker-循环执行 Timer延时功能 停止和重置定时器 定时器Ticker使用 定时器1-"*/5 * * * * *" package main import ( "fmt" "github.com/robfig/cron" ) //主函数 func main() { cron2 := cron.New

  • Vue实现高德坐标转GPS坐标功能的示例详解

    首先介绍一下常见的几种地图的坐标类型: WGS-84:这是一个国际标准,也就是GPS坐标(Google Earth.或者GPS模块采集的都是这个类型). GCJ-02:中国坐标偏移标准,像是Google Map.高德.腾讯地图都是采用这种坐标展示. BD-09:百度坐标偏移标准,百度地图专用的便宜标准. 所以说这篇博文主要是实现GCJ-02坐标转换成WGS-84坐标. 什么时候会用到需要解决坐标转换的问题呢?起因是一个demo,它使用GPS模块采集经纬度数据,然后使用高德地图进行转换,是的,高德

  • SQL实现Excel的10个常用功能的示例详解

    目录 01. 关联公式:Vlookup 02. 对比两列差异 03. 去除重复值 04. 缺失值处理 05. 多条件筛选 06. 模糊筛选数据 07. 分类汇总 08. 条件计算 09. 删除数据间的空格 10. 合并与排序列 SQL笔试题原题 某数据服务公司 某手游公司的SQL笔试题(原题) 某互联网金融公司SQL笔试题(原题) SQL,数据分析岗的必备技能,你可以不懂Python,R,不懂可视化,不懂机器学习.但SQL,你必须懂.要不然领导让你跑个数据来汇......,哦不,你不懂SQL都无

  • RocketMQ实现随缘分BUG小功能示例详解

    目录 正文 实现过程 生产者: 正文 以前公司的产品已经上线20多年了,主要是维护,也就是改bug.每周我们Team会从Jira上拿我们可以改的bug,因为每个团队负责的业务范围不一样,我们团队只能改我们自己业务范围的.这样每周大概有20个左右的新bug,假如团队一共10个人,那么均分就是每人两个,改完下班. 但是这BUG肯定有难有简单,大家肯定都愿意改简单的,在家办公,任务量完了不就等于放假么.开始是自己给自己抢,就忒卷,是欧美项目,所以客服晚上报出来的bug多.有的哥们早上5点起来看有没有新

  • vue3使用自定义指令实现el dialog拖拽功能示例详解

    目录 实现el-dialog的拖拽功能 通过自定义指令实现拖拽功能 实现拖拽功能 使用方式 实现el-dialog的拖拽功能 这里指的是 element-plus 的el-dialog组件,一开始该组件并没有实现拖拽的功能,当然现在可以通过设置属性的方式实现拖拽. 自带的拖拽功能非常严谨,拖拽时判断是否拖拽出窗口,如果出去了会阻止拖拽. 如果自带的拖拽功能可以满足需求的话,可以跳过本文. 通过自定义指令实现拖拽功能 因为要自己操作dom(设置事件),所以感觉还是使用自定义指令更直接一些,而且对原

随机推荐