文章目录
零基础专属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解析器
就够我们喝一壶的,再去定制各种主题更需要花费各种成本,这些就足够劝退一大部分开发者。
写在最后,得益于时代、也将反馈于时代,你我都是践行者!
都看到最后了,觉得还可以的话动动手指点赞、收藏、关注下吧😄,码字不已,坚持更新!
个人主页:http://www.wawow.xyz