438 lines
14 KiB
Markdown
Executable File
438 lines
14 KiB
Markdown
Executable File
## 简介
|
||
一款使用marked和highlight.js开发的一款markdown编辑器,除常见markdown语法外,支持快捷输入、图片粘贴、代码复制、全屏编辑、预览等功能。
|
||
|
||
使用起来简单方便,只需几行代码,即可在你的页面上引入一个markdown编辑器,编辑区支持像专业编辑器那样。
|
||
|
||
编辑器涵盖了常用的markdown编辑器功能,可通过已有属性进行配置,对编辑器功能和样式进行基本的配置,也可根据需求进行深度定制。
|
||
#### [项目地址](https://github.com/zhaoxuhui1122/vue-markdown)
|
||
#### [文档地址](https://zhaoxuhui1122.github.io/vue-markdown-docs/)
|
||
**示例**
|
||
![image.png](https://upload-images.jianshu.io/upload_images/9390764-f6b0840eca057d61.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
|
||
|
||
## 特点
|
||
- 使用简单,只需要安装npm包,引入项目即可使用,不需要繁琐的初始化配置。
|
||
- 方便扩展,根据实际需求,支持常见的功能配置,也可根据实际需求进行深度定制。
|
||
- 体积小,加载速度快,npm包删除了highlight.js和codemirror里的依赖。
|
||
- 灵活的主题,默认支持四种代码块风格,也可根据实际需求定制自己的主题样式
|
||
- 功能强大,支持专业版的编辑器,使用codemirror实现编辑窗口,可识别markdown语法
|
||
- 键盘事件监听,如保存、粘贴、回车时上次输入语法判断等
|
||
- 可扩展性强,除了提供的属性配置编辑器,也可直接在原有组件基础上进行二次开发
|
||
|
||
## 实现思路
|
||
|
||
通过监听文本输入区域内内容的变化,实时将输入的markdown语法进行编译,并渲染到预览区域。
|
||
|
||
编辑器大致分为头部菜单栏、左侧内容输入区域、右侧预览区域三个部分。
|
||
头部菜单主要为定自定义标题区域和菜单按钮,菜单按钮可通过配置文件进行显示和隐藏;左侧编辑区域,简单版使用textarea开发,满足基本需求,
|
||
专业版使用codemirror开发,编辑区域支持手动输入文本和通过头部菜单插入;右侧预览区域可实时预览输入文本,并可通过菜单按钮,进行编辑区域和预览区域的切换。
|
||
|
||
## 安装方式
|
||
### 使用npm安装
|
||
|
||
1. 安装依赖
|
||
```
|
||
npm i -S vue-meditor
|
||
```
|
||
|
||
### 将组件复制到项目内
|
||
1. 将git仓库代码拉到本地
|
||
```
|
||
git clone https://github.com/zhaoxuhui1122/vue-markdown.git
|
||
```
|
||
|
||
2. 复制src文件夹下内容至components文件夹下
|
||
|
||
## 在项目使用
|
||
#### npm包安装时
|
||
简单版
|
||
```js
|
||
import Markdown from 'vue-meditor'
|
||
```
|
||
专业版
|
||
```js
|
||
import { MarkdownPro } from 'vue-meditor'
|
||
```
|
||
预览组件
|
||
```js
|
||
import { MarkdownPreview } from 'vue-meditor'
|
||
```
|
||
#### 复制组件到本地时(推荐)
|
||
简单版
|
||
```js
|
||
import Markdown from '@/components/markdown/...';
|
||
```
|
||
专业版
|
||
```js
|
||
import MarkdownPro from '@/components/markdown/pro';
|
||
```
|
||
预览组件
|
||
```js
|
||
import MarkdownPreview from '@/components/markdown/preview';
|
||
```
|
||
|
||
#### 在页面内使用
|
||
```vue
|
||
<template>
|
||
<div class="markdown">
|
||
<Markdown/>
|
||
</div>
|
||
</template>
|
||
|
||
<script>
|
||
import Markdown from 'vue-meditor';
|
||
|
||
export default {
|
||
name: "markdown",
|
||
components: {
|
||
Markdown
|
||
}
|
||
}
|
||
</script>
|
||
```
|
||
## API
|
||
### 编辑器基本属性
|
||
#### value
|
||
- Type: `String/Number`
|
||
- Default: `''`
|
||
|
||
编辑器输入的文本,支持通过`v-dodel`数据双向绑定设置编辑器内容和获取编辑器的值。
|
||
|
||
#### width
|
||
- Type: `String/Number`
|
||
- Default: `auto`
|
||
|
||
编辑器的初始化宽度。
|
||
|
||
#### height
|
||
- Type: `Number`
|
||
- Default: `600`
|
||
|
||
编辑器的初始化高度。
|
||
|
||
#### bordered
|
||
- Type: `Boolean`
|
||
- Default: `true`
|
||
|
||
编辑器是否含有边框。
|
||
|
||
#### toolbars
|
||
- Type: `Object`
|
||
- Default: `参见下表`
|
||
|
||
头部菜单按钮,通过设置true or false控制决定是否显示,目前配置支持持控制按钮显示隐藏,后续将支持根据配置显示排列顺序。
|
||
|
||
名称 | 说明 | 默认是否显示
|
||
---|---|---
|
||
strong|粗体|是
|
||
italic|斜体|是
|
||
overline |删除线|是
|
||
h1 |标题1|是
|
||
h2 |标题2|是
|
||
h3 |标题3|是
|
||
h4|标题4|否
|
||
h5 |标题5|否
|
||
h6 |标题6|否
|
||
hr |分割线|是
|
||
quote|引用|是
|
||
ul |无序列表|是
|
||
ol|有序列表|是
|
||
code |代码块|是
|
||
link |链接|是
|
||
image|image|是
|
||
table |表格|是
|
||
checked|已完成列表|是
|
||
notChecked |未完成列表|是
|
||
preview|预览|是
|
||
split|分屏模式切换|是
|
||
print |打印|否
|
||
theme|主题切换|是
|
||
fullscreen |全屏|是
|
||
exportmd|导出为*.md文件|是
|
||
importmd|导入本地*.md文件|是
|
||
save|保存按钮|否
|
||
clear|清空内容|否
|
||
|
||
|
||
#### theme
|
||
- Type: `String`
|
||
- Default: `light`
|
||
|
||
编辑器代码块主题,目前支持`light`、`dark`、`oneDark`、`gitHub`四种代码块风格,可通过自定义theme并修改样式文件进行主题定制。
|
||
|
||
自定义theme时,预览区域的会增加一个为`markdown-theme-[theme]`的`class`。
|
||
|
||
|
||
#### autoSave
|
||
- Type: `Boolean`
|
||
- Default: `false`
|
||
|
||
是否开启自动保存,设置为开启时可通过绑定`on-save`事件获取编辑器内的值和代码块主题。
|
||
```vue
|
||
<Markdown @on-save="handleOnSave"/>
|
||
```
|
||
```js
|
||
handleOnSave({value, theme}){
|
||
console.log(value, theme);
|
||
}
|
||
```
|
||
#### interval
|
||
- Type: `Number`
|
||
- Default: `10000`
|
||
|
||
自动保存间隔时间,单位:`mm`,默认10000mm,需要`autoSave = true`时才有效。
|
||
|
||
#### exportFileName
|
||
- Type: `String`
|
||
- Default: `unnamed`
|
||
|
||
导出的md文件名称,默认unnamed.md。
|
||
|
||
#### markedOptions
|
||
- Type: `Object`
|
||
- Default: `{}`
|
||
|
||
marked配置项,可以根据需求自定义。
|
||
|
||
```vue
|
||
<Markdown :markedOptions="{baseUrl:'http://***.oss-cn-shanghai.aliyuncs.com/'}"/>
|
||
```
|
||
#### isPreview
|
||
- Type: `Boolean`
|
||
- Default: `false`
|
||
|
||
是否是预览模式,开启时可作为一个预览组件使用,与预览组件功能一致。
|
||
|
||
#### copyCode
|
||
- Type: `Boolean`
|
||
- Default: `true`
|
||
|
||
是否支持复制代码块内的内容。
|
||
|
||
#### copyBtnText
|
||
- Type: `String`
|
||
- Default: `复制代码`
|
||
|
||
复制代码按钮显示文字。
|
||
|
||
|
||
### 预览组件基本属性
|
||
#### initialValue
|
||
- Type: `String/Number`
|
||
- Default: `''`
|
||
|
||
预览组件初始化内容,支持动态更新。
|
||
|
||
#### theme
|
||
- Type: `String`
|
||
- Default: `light`
|
||
|
||
代码块主题,与编辑器编辑器代码块主题一致。
|
||
|
||
#### markedOptions
|
||
- Type: `Object`
|
||
- Default: `{}`
|
||
|
||
marked配置项,与编辑器内该配置一致。
|
||
|
||
#### copyCode
|
||
- Type: `Boolean`
|
||
- Default: `true`
|
||
|
||
是否支持复制代码块内的内容。
|
||
|
||
|
||
#### copyBtnText
|
||
- Type: `String`
|
||
- Default: `复制代码`
|
||
|
||
复制代码按钮显示文字。
|
||
### on-ready
|
||
编辑器初始化完成时触发,返回值为`Object`,包含组件本身和`insertContent`方法。
|
||
|
||
#### on-save
|
||
编辑器保存事件,自动保存或者手动保存时触发,支持`ctrl+s`或`command+s`触发保存,返回值类型为`Object`,包含当前输入值`value`和选择的代码块主题`theme`。
|
||
|
||
|
||
#### on-paste-image
|
||
|
||
监听编辑器粘贴图片事件,在编辑区域内手动粘贴图片时触发,可用于支持粘贴插入图片文件,返回`file`文件,上传文件后可结合`on-ready`事件内返回的`insertContent`插入图片。
|
||
|
||
#### on-copy
|
||
复制代码块内容,触发时返回当前代码块的text,copyCode开启时才有效。
|
||
|
||
## 二次开发
|
||
### 粘贴插入图片
|
||
|
||
`on-paste-image`虽然可以支持图片粘贴事件的监听,但不会处理图片上传至服务器并将链接插入编辑器这段逻辑。
|
||
|
||
目前如果想要支持粘贴插入图片,需要在`on-paste-image`方法里上传图片文件,拿到图片地址后,使用`on-ready`方法里返回的insertContent方法插入图片。
|
||
|
||
上述操作显得过于复杂,可以直接在源码里扩展mixins里的`handlePaste`方法,图片上传完成后,直接调用`this.insertContent`方法插入图片。
|
||
|
||
修改`/markdown/mixins/common.js`
|
||
|
||
```js
|
||
handlePaste(_, e) {// 粘贴图片
|
||
const { clipboardData = {} } = e;
|
||
const { types = [], items } = clipboardData;
|
||
let item = null;
|
||
for (let i = 0; i < types.length; i++) {
|
||
if (types[i] === 'Files') {
|
||
item = items[i];
|
||
break;
|
||
}
|
||
}
|
||
if (item) {
|
||
const file = item.getAsFile();
|
||
if (/image/gi.test(file.type)) {
|
||
e.preventDefault();
|
||
// 1.上传操作
|
||
// 2.插入图片 this.insertContent(`![image](imgUrl)`)
|
||
}
|
||
}
|
||
}
|
||
```
|
||
### 支持流程图、甘特图等语法
|
||
|
||
目前编辑器只支持常见code语法,如果需要实现如流程图等功能,需要进一步扩展,以实现一个简单的流程图为例,具体实现思路如下:
|
||
|
||
默认情况下,markedjs会使用renderer.code方法对输入的代码块进行解析,并会借助`highlight.js`支持语法高亮。
|
||
可以将流程图语法输入到代码块内,并标明语言,重写marked.Renderer的code解析方法,结合结合`flowchart.js`路程图代码进行解析,返回文本内容。
|
||
|
||
修改`/markdown/libs/js/simple.js
|
||
|
||
```js
|
||
import hljs from './hljs';
|
||
import index from 'index';
|
||
import {parse} from 'flowchart.js'
|
||
|
||
hljs.initHighlightingOnLoad();
|
||
|
||
const renderer = new index.Renderer();
|
||
renderer.code = (code, language) => {
|
||
if (language === 'flow') {// 流程图
|
||
const dom = document.createElement('div');
|
||
const flowchart = parse(code);
|
||
flowchart.drawSVG(dom, {/*相关配置*/});
|
||
return dom.innerHTML;
|
||
} else {// 默认解析
|
||
return `<pre class="hljs"><code class="${language}">${hljs.highlightAuto(code).value}</code></pre>`
|
||
}
|
||
}
|
||
export default index.setOptions({
|
||
renderer,
|
||
gfm: true,
|
||
tables: true,
|
||
breaks: false,
|
||
pedantic: false,
|
||
sanitize: false,
|
||
smartLists: true,
|
||
highlight: function (code) {
|
||
return hljs.highlightAuto(code).value;
|
||
}
|
||
})
|
||
```
|
||
|
||
### 自定义markdown语法转换
|
||
|
||
项目内使用的`index.js均为其默认配置功能,如需要特殊转换,可重写其内部的解析方法,即重写其renderer相关方法
|
||
[参考文档](https://github.com/markedjs/marked/blob/master/docs/USING_PRO.md)。
|
||
|
||
## 自动生成文档目录
|
||
|
||
预览区域和文档预览组件暂不支持自动生成目录,实现自动生成目录思路目前想到的大致有
|
||
- 重写`renderer.heading` 方法,为生成的标题添加id,输入特定快捷键,如`[TOC]`时,查找预览区域内的的所有标题标签,分析等级关系,生成目录标签
|
||
属性 | 说明| 类型| 默认值
|
||
-|-|-|-
|
||
affix |固定模式| Boolean |true
|
||
offset-top |距离窗口顶部达到指定偏移量后触发 |Number| 0
|
||
offset-bottom |距离窗口底部达到指定偏移量后触发| Number| -
|
||
bounds| 锚点区域边界,单位:px| Number| 5
|
||
scroll-offset| 点击滚动的额外距离| Number| 0
|
||
container| 指定滚动的容器 |String | HTMLElement| -
|
||
show-ink| 是否显示小圆点| Boolean |false
|
||
### icon替换
|
||
项目内所有的icon和命名参考`/assets/font/index.html`,替换时需注意,预览区域的checkbox为icon,注意一并替换,
|
||
修改`/assets/css/index.less`内的`input[type="checkbox"]`的`:after`样式。
|
||
|
||
## 代码体积优化
|
||
|
||
|
||
### 公共代码提取
|
||
npm包构建时,三个组件完全独立,没有抽离公共文件,所以,当同一个项目内引入其中的两个或三个组件都引入时,存在一定的重复代码,
|
||
主要为`highlight.js`、`marked`、`iconfont`、css样式几个部分。
|
||
|
||
解决方式:将组件复制到本地项目,打包时将这些文件作为公共文件抽离出来。
|
||
|
||
**注意**:三个组件中使用的iconfont为同一套,如果只是单纯的使用`preview`组件,
|
||
将会引入整个项目所使用的iconfont,可删除iconfont的引入,
|
||
重写`input[type="checkbox"]`的样式,preview组件体积将会减少一半,样式文件位于`markdown/assets/css/index.less`。
|
||
|
||
### codemirror体积优化
|
||
codemirror主要分为主文件、mode相关文件和样式文件,主文件体积异常的大,mode文件目前只选用了css/jsvascript/markdown/meta/xml五个文件,
|
||
其中markdown.js和meta.js为必须引用的,项目中已将常见的编程语言代码风格定义为css/js/xml之一,例如less/sass/scss按照css规则解析,html/vue按照xml规则解析。
|
||
优化可从一下方面入手
|
||
- 减少codemirror主文件体积
|
||
- 减少引用的mode依赖
|
||
|
||
### highlight.js体积优化
|
||
|
||
highlight.js原本体积也是较大的,主要原因为,编译时为支持各种代码语言,引入了相应的解析文件,
|
||
项目内已根据常见的代码语言进行了一次筛选,进行按需引入,可根据自身需求,再次对引用文件进行删减
|
||
|
||
参见`src/markdown/libs/js/hljs.js`,目前支持的语言有
|
||
```js
|
||
import hljs from 'highlight.js/lib/highlight'
|
||
|
||
import javascript from 'highlight.js/lib/languages/javascript'
|
||
import java from 'highlight.js/lib/languages/java';
|
||
import css from 'highlight.js/lib/languages/css';
|
||
import less from 'highlight.js/lib/languages/less';
|
||
import go from 'highlight.js/lib/languages/go';
|
||
import markdown from src;
|
||
import php from 'highlight.js/lib/languages/php';
|
||
import python from 'highlight.js/lib/languages/python';
|
||
import ruby from 'highlight.js/lib/languages/ruby';
|
||
import stylus from 'highlight.js/lib/languages/stylus';
|
||
import typescript from 'highlight.js/lib/languages/typescript';
|
||
import xml from 'highlight.js/lib/languages/xml';
|
||
|
||
const languages = {
|
||
javascript,
|
||
java,
|
||
css,
|
||
less,
|
||
markdown,
|
||
go,
|
||
php,
|
||
python,
|
||
ruby,
|
||
stylus,
|
||
typescript,
|
||
xml
|
||
}
|
||
Object.keys(languages).forEach(key => {
|
||
hljs.registerLanguage(key, languages[key])
|
||
})
|
||
|
||
export default hljs;
|
||
```
|
||
|
||
### 专业版编辑器codemirror/simple.js
|
||
优化思路:无
|
||
#### iconfont 体积优化
|
||
只需要preview组件时,避免引入所有icon,参考功能扩展里icon替换方法。
|
||
|
||
## 升级路线
|
||
- 普通版编辑器对选中文本进行操作功能
|
||
- 文档目录功能
|
||
- 优化专业版编辑器体积
|
||
- react版开发
|
||
- ...
|
||
|
||
## 问题反馈
|
||
|
||
对于功能上的缺陷、使用方法和希望扩展的功能,可以提 [Issues](https://github.com/zhaoxuhui1122/vue-markdown/issues)。
|
||
|
||
## license: `MIT`
|