零基础专属Markdown在线编辑器开发

·  阅读 484
零基础专属Markdown在线编辑器开发

零基础专属Markdown在线编辑器开发

在线案例

Markdown也是标记语言一种,类似HTML,和CSS没关系。我们平时使用和看到的Markdown编辑器(Typora等)显示的样式都是转换为HTML后,再加上内置样式的CSS展示的;

而如今,Markdown写作 + HTML展示的方式不再局限于客户端写作,越来越受到各种网站的青睐,尤其以博客/论坛网站为主,例如掘金社区CSDN博客园等;这些网站的共同点都提供作者在线书写和编辑文章的功能,并且基本都遵循Markdown写作 + HTML展示模式;

1、Markdown和HTML

1)名字区别

HTML全称 hypertext markup language (超文本标记语言),其中着重关注下单词 markup ,译为标记

对照下markdown ,刚好和 markup 相反,因此我们暂时可以理解markdown反标记的意思;

2)功能区别

HTML关注的重点是内容的展示,包含形式、样式、格式等;对于一个页面用户而言,只要页面展示够优美就行,不会关注源码的简单或者复杂;单纯的HTML能够显示内容的基本样式,比如h1、h2···标题等,配合CSS样式赋予内容更优美的呈现。

Markdown更关注内容(源码)的书写方式和规则,简单高效的的书写和规则让使用者事半功倍;所以,Markdown的主要用户是内容生成者,例如文档撰写者等。

2、Markdown转HTML

Markdown(后面全部以MD表示)转为HTML的原理其实并不难,本质上是字符串的转换,例如识别到# 一级标题的MD内容,判断为# #加空格开头,\n换行结尾,对应的生成<h1>一级标题</h1>HTML字符串内容。当然实际上针对所有格式进行转化远比我所描述的复杂,就比如核弹的原理和生产图纸早就是公开的,但是能造核弹的也就那么几个国家。

现在Markdown转HTML的库已经有很多了,因此我们也可以省去造轮子,直接站在巨人的肩膀上进行我们的开发;本文讲述的MD在线编辑器的实现使用技术Vite+Vue3+TypeScript+markedjs

先看成果图:(在线编辑+保存+更换主题等)

1)marked.js

回到本文,在经过简单调研后我最终选择用marked.js进行Markdown到HTML的转化操作;跟大多数node库的安装和使用方式一样:

// 安装
npm install marked
// 引入(ES模块)
import { marked } from "marked";
// 使用 mdStr:markdown文本数据,html:转化后的html格式文本数据
let html = marked.parse(mdStr)
复制代码

2)Markdown转HTML展示

1、定义md2html函数

// mdParser.ts
import { marked } from "marked";

export async function md2html(mdStr: string) {
    let html = await marked.parse(mdStr)
    return html;
}
复制代码

2、在线html内容渲染(v-html)

通过marked将MD转为HTML,然后通过v-html将转化的htmlValue绑定到定义好的div上,一个简单的md转为html在线渲染页面就实现了;

// mdEditor.vue
<template>
  ···
	<div class="markdown-body" id="markdown" v-html="htmlValue"></div>
</template>

<script lang='ts'>
  ···
  import { md2html } from '../utils/mdParser';
  ···
  
  export default defineComponent({
    setup() {
      ···
      let mdValue = ref<string>('');
    	let htmlValue = ref<string>('');
      ···
      htmlValue.value = await md2html(mdValue.value);
      return {
        htmlValue
      }
    }
  })
</script>
复制代码

3)MD在线编辑和HTML实时渲染

  • 划分页面区域:MD编辑区(textarea实现)、HTML渲染区(v-html);
  • 监听MD编辑区数据变化、实时更新HTML渲染区;
// mdEditor.vue
<template>
  ···
					<div class="editor-area">
                ···
                    <div class="m-text">
                        <a-textarea
                            id="text-area"
                            class="m-textarea boxshadow"
                            v-model:value="mdValue"
                            style="padding: 10px"
                        />
                    </div>
          
                ····
                    <div class="m-lr boxshadow">
                        <div class="markdown-body" id="markdown" v-html="htmlValue"></div>
                    </div>
               ···
        </div>
	···
</template>

<script lang='ts'>
  ···
  import { md2html } from '../utils/mdParser';
  ···
  
  export default defineComponent({
    setup() {
      ···
      let mdValue = ref<string>('');
    	let htmlValue = ref<string>('');
      ···
      watch([mdValue], async () => {
        let md = await md2html(mdValue.value);
        htmlValue.value = md;
      });
      return {
        htmlValue,
        mdValue
      }
    }
  })
</script>
复制代码

4)更换MD主题

主题其实是一系列的CSS样式,分别对MD转为HTML中的各种元素进行CSS样式设置,这里我就偷懒了,直接借鉴了 掘金 的一部分主题;打开文章源码,可以看到掘金MD区域做了明显的区分,对比所有主题,发现MD区域的类写死为markdown-body,并且相关主题的CSS样式直接放在了该dom下,这就很方便我们借鉴了😂

具体如何借鉴如下:

  • 找到掘金文章的MD渲染区域(红框部分);
  • 复制style标签中的样式(绿框部分);
  • 将主题CSS样式存放在数据库了,方便获取、更换和渲染;

当然,如果有时间和精力的小伙伴可以直接手写主题样式,想我这样借鉴(偷)是在不可取!

最终成功如图:

直接上代码:

<template>
    				···
                <div class="m-b">
                    选择主题:
                    <a-select
                        style="margin-right: 10px; width: 200px"
                        v-model:value="selectTheme"
                        :options="options"
                    ></a-select>
                </div>
                ····
        <div class="editor-area">
            ···
                        <a-textarea
                            id="text-area"
                            class="m-textarea boxshadow"
                            v-model:value="mdValue"
                            style="padding: 10px"
                        />
                ···
                    <div class="m-lr boxshadow">
                        <div class="markdown-body" id="markdown" v-html="htmlValue"></div>
                    </div>
             ···
        </div>
    </a-card>
</template>

<script lang='ts'>
···
import { defineComponent, onMounted, reactive, ref, watch } from 'vue';
import { md2html } from '../utils/mdParser';
import { getAllTheme } from '../api/blog';
  
export default defineComponent({
    ···
    setup() {
  			···
        let mdValue = ref<string>('');
        let htmlValue = ref<string>('');
        let selectTheme = ref<string>('');
        let mdTitle = ref<string>('');
        let options = reactive<Array<{ value: string; label: string }>>([]);
  			···
				// 接口获取所有主题样式
        const getTheme = async () => {
            const theme: any = await getAllTheme();
            theme.forEach((item) => {
                options.push({
                    label: item.theme,
                    value: item.style,
                });
            });
          	// 默认选中第一个主题
            selectTheme.value = options[0].value;
        };
        onMounted(getTheme);
      	// 监听主题和md内容变化
        watch([mdValue, selectTheme], async () => {
            let md = await md2html(mdValue.value);
            htmlValue.value = selectTheme.value ? selectTheme.value + md : md;
        });
        return {
            selectTheme,
            options,
            mdValue,
            htmlValue,
            mdTitle,
            chnageType,
        };
    },
});
</script>
复制代码

5)文件保存

这里使用file-saver进行不同格式数据的保存,具体使用方法百度/谷歌看文档就行,很简单!

总结

通过上面的内容不难发现,原来开发一个MD在线编辑器并不难,一方面得益于前端生态的强大和全面,一方面得益于对优秀项目的学习和借鉴,要不然光是写一个原生的MD解析器就够我们喝一壶的,再去定制各种主题更需要花费各种成本,这些就足够劝退一大部分开发者。

写在最后,得益于时代、也将反馈于时代,你我都是践行者!

都看到最后了,觉得还可以的话动动手指点赞、收藏、关注下吧😄,码字不已,坚持更新!

个人主页:www.wawow.xyz

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