前言
其实在之前写过一篇关于tui.editor集成的文章,主要目的不是要告诉大家如何去集成,这些在官方的文档上都可以查阅。主要是记录一下在集成中遇到的问题和如何解决这些问题的过程。
本篇是由之前的v1.3.3升版至v2.1.0,改动还真的不小。不过升级之后呢有些之前的bug解决了,整个风格也有所变化。当然之前有关于自定义toolbar的疑惑也得到解决啦!之所以想要升版,是最近越来越多的同事在使用这个markdown编辑器,而且文档的编辑内容越来越长,在markdown模式下来回联滚的时候左右内容显示不一致,后来看了官方的文档和最近的更新历史有解决过这个问题,所以考虑升级。不过也发现了很多新内容,比如说有针对vue的vue-editor,还有react-editor、jquery-editor、editor(基础版),这些之前都是没有的。虽然我也是在vue的项目中使用,但是最后还是决定使用最基础的,这个后面会加以说明。
先安装
$ npm install --save @toast-ui/editor
再引入:
import Editor from '@toast-ui/editor';
import 'codemirror/lib/codemirror.css'; // Editor's Dependency Style
import '@toast-ui/editor/dist/toastui-editor.css'; // Editor's Style
import '@toast-ui/editor/dist/i18n/zh-cn';
import uml from '@toast-ui/editor-plugin-uml';//uml plugin
// import 'tui-color-picker/dist/tui-color-picker.css';//背景色plugin样式
// import colorSyntax from '@toast-ui/editor-plugin-color-syntax';//背景色plugin
//mermaid插件
import mermaid from 'mermaid'
//markmap插件
import 'markmap/style/view.mindmap.css'
require('markmap/lib/d3-flextree');
const markmap = require('markmap/lib/view.mindmap');
const parse = require('markmap/lib/parse.markdown');
const transform = require('markmap/lib/transform.headings');
1.新建实例(预览模式)
initEditor() {
let _this = this;
//初次加载 显示md预览页 创建预览实例
let sets = {
height: _this.height,
language:'zh-CN',
viewer: true,//先创建的的是预览模式
initialValue: '',
toolbarItems: [
'heading',
'bold',
'italic',
'strike',
'divider',
'hr',
'quote',
'divider',
'ul',
'ol',
'task',
'indent',
'outdent',
'divider',
'table',
// 'image',
'link',
'divider',
'code',
'codeblock'
],
plugins: [uml,this.mindmapPlugin,this.mermaidPlugin]
};
this.editor = Editor.factory({
el: this.$refs.viewer,
...sets
})
//mermaid配置
let config = {
theme: 'neutral',//'default', 'forest', 'dark', 'neutral'
logLevel: 'fatal',
securityLevel: 'strict',
startOnLoad: true,
arrowMarkerAbsolute: false,
flowchart: {
htmlLabels: false, //设为true宽度会变窄
curve: 'linear',//cardinal
useMaxWidth: true,
},
sequence: {
diagramMarginX: 50,
diagramMarginY: 10,
actorMargin: 50,
width: 150,
height: 65,
boxMargin: 10,
boxTextMargin: 5,
noteMargin: 10,
messageMargin: 35,
mirrorActors: true,
bottomMarginAdj: 1,
useMaxWidth: true,
rightAngles: false,
showSequenceNumbers: false,
},
gantt: {
titleTopMargin: 25,
barHeight: 40,
barGap: 5,
topPadding: 50,
leftPadding: 75,
gridLineStartPadding: 35,
fontSize: 11,
fontFamily: '"Open-Sans", "sans-serif"',
numberSectionStyles: 4,
axisFormat: '%Y-%m-%d',
}
};
mermaid.flowchartConfig = {
width: '100%',
}
mermaid.initialize(config);
},
特别需要注意的是plugins参数,在老版本里面可不是叫plugins,叫exts,而且老版本里面存放的都是一些自己扩展的插件名称,但是新版本就不同了,可以存放方法。可以注意一下我的写法this.mindmapPlugin,this.mermaidPlugin这两个都 是有返回值的函数;上面代码使用 Editor.factory新建的是markdown预览模式,如果点击编辑,可使用new Editor新建markdown模式。也许有的需求可能不一样不需要预览,直接一上来就展示markdown,这些都可以随自己的需求新建需要的模式的;
2.插件注入
示例如下:
mermaidPlugin(){
Editor.codeBlockManager.setReplacer('mermaid', function (content) {
var mermaidId = 'mermaid-' + Math.random().toString(36).substr(2, 10);
setTimeout(renderMermaid.bind(null, mermaidId, content), 0);
return '';
});
function renderMermaid(mermaidId, content) {
var el = document.querySelector('#' + mermaidId);
const cb = function (svgGraph) {
el.innerHTML = svgGraph;
};
const id = mermaidId + "-svg"
mermaid.render(id, content, cb);
}
},
mindmapPlugin(){//mindmap插件注入 脑图部分
Editor.codeBlockManager.setReplacer('mindmap', function (content) {
var mindmapId = 'mindmap-' + Math.random().toString(36).substr(2, 10);
setTimeout(renderMindmap.bind(null, mindmapId, content), 0);
let h = content.split(" ").length * 30;
return ``;
});
function renderMindmap(mindmapId, content) {
var el = document.querySelector('#' + mindmapId);
const id = mindmapId + "-svg"
setTimeout(() => {
markmap('#' + id, transform(parse(content)), {
preset: 'default', // or colorful
linkShape: 'diagonal' // or bracket
});
}, 0)
el.innerHTML = ``;
}
},
这里使用到了Editor,其实吧使用vue-editor真的超级简便,但是扩展额外的插件时候愣是取不到Editor,被封装起来了。所以这也是我采用基础版的原因;还有插件注入这部分改动也不小,之前的版本API直接就不能用了,不过新版更好用;
3.自定义toolbar
initToolbars() {
let _this = this;
let toolbar = _this.editor.getUI().getToolbar();
//上传图片
_this.editor.eventManager.addEventType('insertImg');
_this.editor.eventManager.listen('insertImg', function() {
_this.insertImgClick();
});
toolbar.insertItem(toolbar.getItems().length - 1, {
type: 'button',
options: {
name: 'toolbar-item',
className: 'toast toast-img-icon',//自定义按钮的类名
event: 'insertImg',//对应上文的eventManager添加的监听事件类型,通过点击触发
tooltip: '上传图片',//鼠标hover自定义按钮的提示信息
}
});
//网盘链接
_this.editor.eventManager.addEventType('wpClick');
_this.editor.eventManager.listen('wpClick', function () {
_this.wpClick();
});
toolbar.insertItem(toolbar.getItems().length - 1, {
type:'button',
options: {
event: 'wpClick',
tooltip: '添加网盘文件',
el:this.createLastButton('wp'),
style: 'background:none;color:#333;'
}
});
//mermaid扩展
_this.editor.eventManager.addEventType('umlClick');
_this.editor.eventManager.listen('umlClick', function () {
_this.umlClick();
});
toolbar.insertItem(toolbar.getItems().length - 1, {
type:'button',
options: {
event: 'umlClick',
tooltip: '绘制UML图',
el:this.createLastButton('uml'),
style: 'background:none;color:#333;'
}
});
//思维导图
_this.editor.eventManager.addEventType('mindmapClick');
_this.editor.eventManager.listen('mindmapClick', function () {
_this.mindmapClick();
});
toolbar.insertItem(toolbar.getItems().length - 1, {
type:'button',
options: {
event: 'mindmapClick',
tooltip: '思维导图',
el:this.createLastButton('mindmap'),
style: 'background:none;color:#333;'
}
});
//帮助
_this.editor.eventManager.addEventType('helpClick');
_this.editor.eventManager.listen('helpClick', function () {
_this.helpClick();
});
toolbar.insertItem(toolbar.getItems().length - 1, {
type:'button',
options: {
event: 'helpClick',
tooltip: '帮助',
el:this.createLastButton('help'),
style: 'background:none;color:#333;'
}
});
},
不知道有没有注意到createLastButton()这个方法,是用于注册每个自定义toolbar的样式的,这里我采用的是element-ui的icon十分简便;
createLastButton(tag) {//创建不同toolbar图标
const button = document.createElement('button');
if(tag == 'wp'){
button.innerHTML = ``;
}else if(tag == 'uml'){
button.innerHTML = ``;
}else if(tag == 'mindmap'){
button.innerHTML = ``;
}else if(tag == 'help'){
button.innerHTML = ``;
}
return button;
},
写到这里我之前的疑惑也解决了。因为在一开始的1.3.3版本中自定义toolbar是使用addButton这个API才加进去的,但是官方文档说已经弃用建议使用insertItem,但是那个时候呢可能是文档更新了插件没有更新吧,所以一直很纳闷,现在终于可以了。
最后呢,又有一个需求了,由于每个md内容过长,需要有目录。这就涉及到锚点问题,如何加进去呢?有待研究。。。