前言
我在使用这个插件的时候遇到一些问题,因为翻遍了没找到一篇能够实现比较全面功能的插件和文章,所以记录下来,让需要的宝子们少踩坑
1.有关中英文显示。
2.工具栏使用字体颜色插件。
3.自定义插件
一、安装插件
npm install @toast-ui/vue-editor @toast-ui/editor
二、基本使用
2.1 在inde.vue组件中初始化配置tui.editor
<template>
<div id="editor" ref="editor"></div>
</template>
<script>
import '@toast-ui/editor/dist/toastui-editor.css';
import '@toast-ui/editor/dist/toastui-editor-viewer.css';
import Editor from '@toast-ui/editor';
export default {
name: 'markingRecord',
data() {
return {
editor: null,
markdown: `# Hello, World! :icon: ### 被告人谭某某,女,1974
##### 指定辩护人胡建和,广东瑞霆律师事务所律师。
`,
};
},
mounted() {
this.initEditor();
// 必须放mounted里面,放created里面会导致初始化没成功,编辑器不能正常使用
},
methods: {
initEditor() {
this.editor = new Editor({
el: document.querySelector('#editor'),
// 绑定到id为editor的节点
previewStyle: 'vertical',
// 编辑器的预览样式
initialValue: markdown,
// 编辑器的初始内容
initialEditType: 'wysiwyg',
// 编辑器的模式,(编辑模式markdown/所见即所得模式wysiwyg)
hideModeSwitch: true,
// 是否隐藏上面的编辑器模式选项卡
useCommandShortcut: true,
// 是否使用键盘快捷键执行命令(默认是true)
height: '100%',
// 编辑器高度
previewHighlight:false,
// 是否高亮预览区域 (默认false)
});
this.editor.on('change', () => {
//这里是editor内容发生改变执行的方法
//如果要监听内容变化并依据条件执行可以在这里写入触发方法
});
this.editor.on('load', () => {
//设置editor的文本内容靠左(我用的时候是默认居中的,但我需要内容默认靠左所以需要加上这个)
this.editor.exec('textAlign', 'left');
});
},
},
};
</script>
// 下面是样式
<style lang="less" scoped>
.editor-container {
overflow: hidden;
height: 100%;
position: relative;
width: 770px;
}
#editor {
height: 80%;
width: 100%;
}
</style>
三、中文展示
这个插件默认是英文展示的,然后我在使用中文的时候发现一点问题需要去改node文件
3.1 如何配置中文
node_modules目录下找到文件@toast-ui路径是@toast-ui/editor/dist/i18n下zh-cn.js这个文件
在zh-cn.js 文件的107行的位置有这么一行代码:
_editorCore__WEBPACK_IMPORTED_MODULE_0___default().setLanguage('zh-CN',{
将其改为
_editorCore__WEBPACK_IMPORTED_MODULE_0___default().setLanguage(['zh','zh-cn'], {
保存,然后在初始化editor组件index.vue里面import 引入 zh-cn.js文件
import '@toast-ui/editor/dist/i18n/zh-cn'
再index.vue组件里面初始化editor的地方,配置里面加上 language: 'zh',
this.editor = new Editor({
el: document.querySelector('#editor'),
previewStyle: 'vertical',
initialValue: markdown,
initialEditType: 'wysiwyg',
hideModeSwitch: true,
useCommandShortcut: true,
height: '100%',
language: 'zh',
});
这样中文展示就有了
3.2 什么原因导致
我感觉是文档或者插件里面的配置有问题,我改了配置和文档给的示例就能正常使用了
这个插件好像里面开发者有棒子,我在找文档的时候看见的示例默认是韩文,然后对比了一下他的配置和我的配置,并且去里面搜到了刚刚node里面的配置,和官方文档给出的不一致,我就改动了一下
其它的语言js文件进去toast-ui/editor/dist/i18n/****.js的107行那个位置的函数第一个参数都是数组,就中文的js文件(zh-cn.js)里面是个字符串,我就改成数组试试,并且在初始化editor配置language的时候值也是前面数组参数的第一个比如示例是韩文,配的是language: 'ko'
vue组件editor初始化
node_modules/@toast-ui/editor/dist/i18n/ko-kr.js文件107行
是不是有点奇怪,其它的配置都是一致的,就中文的不一致而且还用不了,那我就把它改成一致的,然后就好使了。
四、工具栏使用字体颜色功能
4.1 安装插件
字体颜色是tui.editor支持但是插件不自带的,使用的话需要再装一个插件
npm install @toast-ui/editor-plugin-color-syntax
// 在vue组件初始化editor的地方 引入
import '@toast-ui/editor-plugin-color-syntax/dist/toastui-editor-plugin-color-syntax.css';
import Editor from '@toast-ui/editor';
import colorSyntax from '@toast-ui/editor-plugin-color-syntax';
配置里面加上 plugins: [colorSyntax]
this.editor = new Editor({
el: document.querySelector('#editor'),
previewStyle: 'vertical',
plugins: [colorSyntax],//加上这行代码
initialValue: markdown,
initialEditType: 'wysiwyg',
hideModeSwitch: true,
useCommandShortcut: true,
height: '100%',
});
这个就是展示效果
下面放一个配置字体颜色插件的官方文档
https://github.com/nhn/tui.editor/tree/master/plugins/color-syntax
五、关于自己写自定义工具插件以及问题处理
有两种方法,一种是直接在初始化editor之后在组件里面直接写进去,一种是根据上面的字体颜色类似,在node_modle里面新加一个和字体颜色同级的插件
5.1 方法一:组件内直接加
第一种:直接加在组件代码里面,这种的好处是方便传值,比如要取值,或者通过选中的值做其它操作,要方便一点,但是显得组件代码有点冗余
//首先初始化editor
initEditor() {
var editorInstance;
editorInstance = new Editor({
el: document.querySelector('#editor'),
previewStyle: 'vertical',
initialValue: this.markdown,
initialEditType: 'wysiwyg',
hideModeSwitch: true,
useCommandShortcut: true,
height: '100%',
language: 'zh',
toolbarItems: [
['heading' ],
['bold', 'code','italic'],
['ul', 'ol', 'task', 'indent', 'outdent'], [{
name: 'customFontSizes',
tooltip: '字体',
className: 'toastui-editor-custom-clipboard',
// el: this.createCustomButton(),
command: 'customCommandd'
}],
],
});
this.editor = editorInstance;
this.$data.editor = this.editor;
// 注册自定义命令--字号大小
let _this = this;
setTimeout(() => {//定时器是为了能保证editor初始化成功能在里面调用到this.editor实例
this.editor.addCommand('wysiwyg',//给当前wysiwyg这个模式添加工具,如果是markdown模式需要再写一个,只是把里面的wysiwyg换成markdown,copy一份出来就行,因为我只用一个模式所以这里没有写markdown的
'customCommandd', function (payload) {
let colorPicker = document.querySelector('.tui-fontsize-picker-container');
if (!colorPicker) {
colorPicker = document.createElement('ul');
colorPicker.className = 'tui-fontsize-picker-container';
colorPicker.style.display = 'none'; // 默认隐藏
colorPicker.style.position = 'absolute';
colorPicker.style.top = '44px';
colorPicker.style.left = '226px';
colorPicker.style.zIndex = '9999';
colorPicker.style.background = '#fff';
colorPicker.style.border = '1px solid #e8e8e8';
colorPicker.innerHTML = `
<li>9</li>
<li>10</li>
<li>12</li>
<li>14</li>
<li>18</li>
<li>20</li>
<li>24</li>
<li>28</li>
<li>36</li>
<li>42</li>
<li>48</li>
`;
// 将颜色选择框添加到编辑器工具栏下方
const toolbar = document.querySelector('.toastui-editor-toolbar');
toolbar.appendChild(colorPicker);
}
// 获取颜色选择框中的所有 li 元素
const liElements = colorPicker.querySelectorAll('li');
// 为每个 li 元素绑定 click 事件
liElements.forEach(li => {
li.addEventListener('click', function() {
// 处理点击事件,例如获取当前选中的字号或执行其他逻辑
const selection = _this.editor.getSelectedText();
const fontSize = li.innerHTML;
_this.changeFontSize(fontSize,selection);
});
});
// 切换颜色选择框的显示状态
if (colorPicker.style.display === 'none') {
colorPicker.style.display = 'block';
} else {
colorPicker.style.display = 'none';
}
return true; // 表示命令处理完成
}
);
}, 0);
},
//
changeFontSize(fontSize) {
const { view } = this.editor.wwEditor;
const { tr } = view.state;
const schema = this.editor.wwEditor.getSchema();
const { from, to } = view.state.selection;
const markType = schema.marks.span ;
if (!markType) {
console.error('Mark type for font size is not defined in the schema.');
return;
}
//处理选中的元素
const attrs = { htmlAttrs: { style: `font-size: ${fontSize}px;` } };
const mark = markType.create(attrs);
const transaction = tr.addMark(from, to, mark);
view.dispatch(transaction);
},
注意:样式需要自己调,定位颜色这些效果,根据实际情况来,以及有点问题就是选中的文本改变字号后会覆盖原先里面的style样式,因为我主要用到的是第二种方法,所以这个问题暂时我没处理。这个功能主要是为了工具栏加按钮,可以触发一些当前页面操作的,比如触发一个弹窗,主要目的不是为了写工具进去,还是为了方便按钮跟当前组件的数据交互,如果加文本底色,字号这些操作markdown编辑器内部内容的还是推荐使用下面的方法。还有一个要注意的点是setTimeout使用,为了正确调用this.editor,因为文档上是说可以用 this.editor.on('load',()=>{})这个方法来正确调用实例化后的this.editor但是我没试成功,所以用setTimeout替换了。
5.2 方法二:在插件源文件内添加
第二种:node_modle里面去加,感觉这种操作要简单一点,如果用到看宝子们的情况,觉得哪个好用用哪个。
前面讲到字体颜色需要再装个插件,我们去找到这个插件的路径
node_modle/@toast-ui\editor-plugin-color-syntax就是该插件路径,找到这个文件过后,参照这个文件,复制一份出来,改动里面的方法,改成想要的,主要修改里面两个文件types/index.d.js文件和dit/toastui-editor-plugin-color-syntax.js文件
可以看到index.d.js文件内容是这样的
import type { PluginContext, PluginInfo } from '@toast-ui/editor';
export interface PluginOptions {
preset?: string[];
}
export default function colorPlugin(context: PluginContext, options: PluginOptions): PluginInfo;
我们需要改动的是导出的方法名称,这里字体颜色是用的colorPlugin,我们新增字体大小的话给它改成fontsizePlugin,如下
import type { PluginContext, PluginInfo } from '@toast-ui/editor';
export interface PluginOptions {
preset?: string[];
}
export default function fontsizePlugin(context: PluginContext, options: PluginOptions): PluginInfo;
然后改toastui-editor-plugin-color-syntax.js文件,这个文件里面有个方法colorSyntaxPlugin,全局搜索到这个方法,一处是方法,一处是引用,这两个地方同时改,因为我们是修改字体大小,所以我这里改成了fontSizePlugin,其它地方不管,然后改fontSizePlugin方法里面的内容,来实现字体大小的功能,下面是我这个方法实现的代码
function fontSizePlugin(context, options) {
if (options === void 0) { options = {}; }
var eventEmitter = context.eventEmitter,
i18n = context.i18n,
pmState = context.pmState;
// 实现工具栏样式按钮
var container = document.createElement('div');
container.style.display = 'flex';
container.style.height = '30px';
container.style.marginTop = '7px';
container.style.backgroundColor = '#f1f2f2';
container.style.alignItems = 'center';
var fontSizeList = document.createElement('ul');
var fontSizes = ['10px', '12px', '14px', '16px', '18px', '20px', '22px'];
fontSizeList.style.position = 'absolute';
fontSizeList.className = 'toastui-editor-popup-fontSize';
fontSizeList.style.top = '39px';
fontSizeList.style.left = '166px';
fontSizeList.style.display = 'none';
fontSizeList.style.backgroundColor = '#fff';
fontSizeList.style.zIndex = '1000';
fontSizeList.style.margin = '0';
fontSizeList.style.listStyle = 'none';
// 给选择框点击事件,调用下面的字体修改方法
fontSizes.forEach(function(size) {
var listItem = document.createElement('li');
listItem.textContent = size;
listItem.style.cursor = 'pointer';
listItem.style.padding = '5px';
listItem.addEventListener('click', function() {
input.value = size;
eventEmitter.emit('command', 'fontSize', { selectedFontSize: size });
eventEmitter.emit('closePopup');
fontSizeList.style.display = 'none';
});
fontSizeList.appendChild(listItem);
});
container.appendChild(fontSizeList);
var input = document.createElement('input');
input.setAttribute('type', 'text');
input.setAttribute('placeholder', '20');
input.style.width = '30px';
input.disabled = true;
input.addEventListener('input', function() {
var size = input.value;
if (fontSizes.includes(size)) {
applyFontSize(size);
}
});
var dropdownButton = document.createElement('button');
dropdownButton.setAttribute('type', 'button');
dropdownButton.textContent = '▼';
dropdownButton.style.cursor = 'pointer';
dropdownButton.addEventListener('focus', function() {
fontSizeList.style.display = 'block';
});
dropdownButton.addEventListener('blur', function() {
setTimeout(function() {
fontSizeList.style.display = 'none';
}, 200);
});
dropdownButton.addEventListener('click', function() {
fontSizeList.style.display = fontSizeList.style.display === 'none' ? 'block' : 'none';
});
container.appendChild(input);
container.appendChild(dropdownButton);
function applyFontSize(size) {
var currentEditorEl = getCurrentEditorEl(container, containerClassName);
console.log('Current editor element:', currentEditorEl);
var tr = pmState.tr;
var selection = pmState.selection;
if (!selection || selection.empty) {
console.error('No selection found or selection is empty.');
return;
}
var from = selection.from, to = selection.to;
var attrs = {};
tr.doc.nodesBetween(from, to, function(node, pos) {
if (node.marks) {
node.marks.forEach(function(mark) {
if (mark.type.name === 'span' && mark.attrs.htmlAttrs && mark.attrs.htmlAttrs.style) {
var styles = mark.attrs.htmlAttrs.style.split(';').filter(Boolean);
styles.forEach(function(style) {
var [key, value] = style.split(':').map(function(part) { return part.trim(); });
if (key !== 'font-size') {
attrs[key] = value;
}
});
}
});
}
});
attrs['font-size'] = size;
var styleStr = Object.entries(attrs).map(function([key, value]) {
return key + ": " + value;
}).join('; ');
var markAttrs = { htmlAttrs: { style: styleStr } };
var newMark = pmState.schema.marks.span.create(markAttrs);
tr.addMark(from, to, newMark);
currentEditorEl.focus();
pmState.apply(tr);
}
var toolbarItem = {
name: 'fontSize',
tooltip: '字号',
el: container,
};
return {
//因为我只用 wysiwyg这个模式,所以我有wysiwygCommands这一对象,如果用到了markdown模式需要再加上markdownCommands对象,可以参考toastui-editor-plugin-color-syntax.js里面
wysiwygCommands: {
fontSize: function (_a, _b, dispatch) {
var selectedFontSize = _a.selectedFontSize;
var tr = _b.tr, selection = _b.selection, schema = _b.schema;
if (selectedFontSize && selection && !selection.empty) {
var attrs = {};
tr.doc.nodesBetween(selection.from, selection.to, function(node) {
if (node.marks) {
node.marks.forEach(function(mark) {
if (mark.type.name === 'span' && mark.attrs.htmlAttrs && mark.attrs.htmlAttrs.style) {
var styles = mark.attrs.htmlAttrs.style.split(';').filter(Boolean);
styles.forEach(function(style) {
var [key, value] = style.split(':').map(function(part) { return part.trim(); });
if (key !== 'font-size') {
attrs[key] = value;
}
});
}
});
}
});
attrs['font-size'] = selectedFontSize;
var styleStr = Object.entries(attrs).map(function([key, value]) {
return key + ": " + value;
}).join('; ');
var markAttrs = { htmlAttrs: { style: styleStr } };
var newMark = schema.marks.span.create(markAttrs);
tr.addMark(selection.from, selection.to, newMark);
dispatch(tr);
return true;
}
return false;
},
},
//在工具栏中的定位
toolbarItems: [
{
groupIndex: 0,
itemIndex: 4,
item: toolbarItem,
},
],
};
}
上面已经实现了基本的功能要求,然后就把上面咱们写的插件用起来
其实和文本颜色一样,在editor初始化组件里面先引用
import colorSyntax from '@toast-ui/editor-plugin-color-syntax';
再使用
this.editor = new Editor({
el: document.querySelector('#editor'),
previewStyle: 'vertical',
plugins: [colorSyntax,fontSize],//这个位置引用插件
initialValue: markdown,
initialEditType: 'wysiwyg',
hideModeSwitch: true,
useCommandShortcut: true,
height: '100%',
});
给大家看看vue里面初始化editor里面使用了文本颜色和字体大小的完整代码
<template>
<div id="editor" ref="editor"></div>
</template>
<script>
import '@toast-ui/editor/dist/toastui-editor.css';
import '@toast-ui/editor/dist/toastui-editor-viewer.css';
import colorSyntax from '@toast-ui/editor-plugin-color-syntax';
import Editor from '@toast-ui/editor';
export default {
name: 'markingRecord',
data() {
return {
editor: null,
markdown: `# Hello, World! :icon: ### 被告人谭某某,女,1974
##### 指定辩护人胡建和,广东瑞霆律师事务所律师。
`,
};
},
mounted() {
this.initEditor();
// 必须放mounted里面,放created里面会导致初始化没成功,编辑器不能正常使用
},
methods: {
initEditor() {
this.editor = new Editor({
el: document.querySelector('#editor'),
// 绑定到id为editor的节点
previewStyle: 'vertical',
//这个位置引用插件
plugins: [colorSyntax,fontSize],
// 编辑器的预览样式
initialValue: markdown,
// 编辑器的初始内容
initialEditType: 'wysiwyg',
// 编辑器的模式,(编辑模式markdown/所见即所得模式wysiwyg)
hideModeSwitch: true,
// 是否隐藏上面的编辑器模式选项卡,所以我前面就只写了wysiwyg模式下的方法
useCommandShortcut: true,
// 是否使用键盘快捷键执行命令(默认是true)
height: '100%',
// 编辑器高度
previewHighlight:false,
// 是否高亮预览区域 (默认false)
});
this.editor.on('change', () => {
//这里是editor内容发生改变执行的方法
//如果要监听内容变化并依据条件执行可以在这里写入触发方法
});
this.editor.on('load', () => {
//设置editor的文本内容靠左(我用的时候是默认居中的,但我需要内容默认靠左所以需要加上这个)
this.editor.exec('textAlign', 'left');
});
},
},
};
</script>
// 下面是样式
<style lang="less" scoped>
.editor-container {
overflow: hidden;
height: 100%;
position: relative;
width: 770px;
}
#editor {
height: 80%;
width: 100%;
}
</style>
这样就能看到宝子们加上的插件了,如果要扩展其它插件的话,和上面步骤一样就能实现,比如添加下划线,删除线这些,因为有的插件和原来的可能有冲突,比如会覆盖掉原来的样式,就需要自己去考虑怎么做了。
5.3 插件在工具栏位置
还有一个点就是工具插件在工具栏的位置,因为工具栏里面的工具是一个二维数组,所以我们在写插件方法的时候需要自己去修改,toolbarItems有个这个参数,
//在工具栏中的定位
toolbarItems: [
{
groupIndex: 0,//第几组
itemIndex: 4,//第几位
item: toolbarItem,
},
]
箭头表示当前分组的地方
5.4 一些editor初始化过后调用的方法
this.editor = new editor({});
this.editor.getSelectedText();//获取当前鼠标选择文本内容
this.editor.on('change', () => {//当编辑器里面内容发生变化时触发
// console.log('text------', this.editor.getMarkdown());
});
this.editor.getMarkdown(); //获取当前编辑器里面的markdown内容
this.editor.getHTML(); //获取编辑器内html内容
this.editor.insertText("123"); //光标所处位置或者选择位置内容替换
this.editor.deleteSelection(); //删除选中的文本
5.5 注意
因为宝子们写的插件是放进node_modle里面的,如果下次装node_modle或者需要 npm i 新增其它插件等各种原因导致node_modle变动,就可能会使我们写的插件被清掉,可以通过把我们写的那块整个文件保存然后每次去将这个插件覆盖,但是有点麻烦,所以我选选择的是直接将插件源码放进代码本地,不放到node_modle里面
在node_modle里面找到@toast-ui文件,整个文件移动到项目里面某个位置,我是放进lib文件夹下面新建一个toast-editor文件,再把node_modle里面的@toast-ui文件里面内容全放进去
然后在初始化editor组件里面调用,记得引用正确路径
import '../../lib/toast-editor/editor/dist/toastui-editor.css';//工具栏样式
import './../../lib/toast-editor/editor/dist/i18n/zh-cn.js';//中文
import Editor from './../../lib/toast-editor/editor/dist/esm/index.js';//editor引用
import colorSyntax from './../../lib/toast-editor/editor-plugin-color-syntax';//字体颜色
import fontSize from './../../lib/toast-editor/editor-plugin-fontsize-syntax';//字体大小
import del from './../../lib/toast-editor/editor-plugin-del-syntax';//删除线
import bgcolor from './../../lib/toast-editor/editor-plugin-bgcolor-syntax';//文本突出显示颜色
import fontfamily from './../../lib/toast-editor/editor-plugin-fontfamily-syntax';//字体
import underline from './../../lib/toast-editor/editor-plugin-underline-syntax';//下划线
import 'tui-color-picker/dist/tui-color-picker.css';//文本颜色样式1
import './../../lib/toast-editor/editor-plugin-color-syntax/dist/toastui-editor-plugin-color-syntax.css';//文本颜色样式2(1,2两个都要)
上面是我自己引用的路径,宝子们自己放的位置引用的话一定要引用正确,还有就是源码如果放进本地的话记得删除package.json里面有关toast-ui的插件和node_modle里面的@toast-ui这个文件
到这里基本就结束了对这个插件的讲解,如果还有什么问题,请评论区留言。