> 文章列表 > 在Vue项目中使用tinymce富文本编辑器

在Vue项目中使用tinymce富文本编辑器

在Vue项目中使用tinymce富文本编辑器

TinyMC编辑器简介

TinyMCE是一款易用、且功能强大的所见即所得的富文本编辑器。跟其他富文本编辑器相比,有着丰富的插件,支持多种语言,能够满足日常的业务需求并且免费。

TinyMCE的优势:

开源可商用,基于LGPL2.1

插件丰富,自带插件基本涵盖日常所需功能

接口丰富,可扩展性强,有能力可以无限拓展功能

界面好看,符合现代审美

提供经典、内联、沉浸无干扰三种模式(详见“介绍与入门”)

对标准支持优秀(自v5开始)

多语言支持,官网可下载几十种语言。

下图为我开启全部功能的截图

TinyMCE中文文档地址:TinyMCE中文文档中文手册

1、安装

vue-cli版本:3.x+

安装tinymce

npm install tinymce@6.3 -S 

安装tinymce-vue

npm install --save tinymce "@tinymce/tinymce-vue@^5"

这两个组件安装完之后,在public目录下新建文件夹tinymce,目录建好后,找到node_modules文件夹下的tinymce/skins目录,将skins目录复制到我们创建的tinymce文件夹内。

vue-cli版本:2.x

安装tinymce,我安装的是5.10.7

npm install tinymce@5.10.7 -S 

安装tinymce-vue

npm install --save tinymce "@tinymce/tinymce-vue@^3"

安装之后,在 node_modules 中找到 tinymce/skins 目录,然后将 skins 目录拷贝到 public/tinymce 目录下

注意: 如果是使用 vue-cli 3.x 之前构建的 typescript 项目,就放到 static 目录下,和文中所有 public 目录一样处理

tinymce 默认是英文界面,所以还需要下载一个中文语言包

然后将这个语言包放到相同 public/tinymce 目录下新建的langs文件目录中

这个是vue-cli3项目的放法

2、配置中文语言

到官网下载中文语言包 zh_CN.js

在刚才创建的static/tinymce文件夹内再新建langs文件夹,用来存放我们下载的中文语言包,如下图所示

 vue-cli2.x 同理

​​3.组件

<template><Editor id="tinymce" v-model="content" :init="init"></Editor>
</template><script>
import tinymce from "tinymce";
import Editor from "@tinymce/tinymce-vue";
import "tinymce/themes/silver/theme";
import "tinymce/plugins/image";
import "tinymce/plugins/link";
import "tinymce/plugins/code";
import "tinymce/plugins/table";
import "tinymce/plugins/lists";
import "tinymce/plugins/wordcount";
import "tinymce/icons/default/icons";
import "tinymce/themes/silver";
import "tinymce/plugins/media";
import "tinymce/plugins/contextmenu";
import "tinymce/plugins/colorpicker";
import "tinymce/plugins/textcolor";
import "tinymce/plugins/preview";
import "tinymce/plugins/advlist";
import "tinymce/plugins/codesample";
import "tinymce/plugins/hr";
import "tinymce/plugins/fullscreen";
import "tinymce/plugins/textpattern";
import "tinymce/plugins/searchreplace";
import "tinymce/plugins/autolink";
import "tinymce/plugins/directionality";
import "tinymce/plugins/visualblocks";
import "tinymce/plugins/visualchars";
import "tinymce/plugins/template";
import "tinymce/plugins/charmap";
import "tinymce/plugins/nonbreaking";
import "tinymce/plugins/insertdatetime";
import "tinymce/plugins/imagetools";
import "tinymce/plugins/autosave";
import "tinymce/plugins/autoresize";
import "tinymce/plugins/paste";
import "tinymce/plugins/print";
import "tinymce/plugins/quickbars";
import "tinymce/plugins/emoticons";
import "tinymce/plugins/bbcode";
import "tinymce/plugins/tabfocus";
// 扩展插件
// import "/tinymce/plugins/lineheight/plugin";
// import "/tinymce/plugins/bdmap/plugin";import { uploadImageFile, deleteFile } from "@/api/geekplus/articles";
export default {name: "TinyEditor",components: { Editor },props:{value: {type: String,default: "",},},data() {return {content: "",//fileList: [],allImageList: [],baseHost: window.location.host,baseApi: process.env.VUE_APP_BASE_API,init: {language_url: "/tinymce/langs/zh_CN.js", // 语言包位置,因为放在public下所以可以省略publicselector: "#tinymce", //tinymce的id// auto_focus: 'element1',language: "zh_CN", //语言类型skin_url: "/tinymce/skins/ui/oxide",height: 650, //编辑器高度min_height: 400,highlight_on_focus: true,// contextmenu_never_use_native: true,//5.0.1draggable_modal: true,//inline: true,// content_style: "p {margin: 2px 0;}",init_instance_callback: (editor) => {// 更改元素为Diveditor.execCommand('mceInsertContent', false, '<p></p>')},browser_spellcheck: true, // 拼写检查// elementpath: false, //禁用编辑器底部的状态栏// statusbar: false, // 隐藏编辑器底部的状态栏// paste_data_images: true, // 允许粘贴图像// menubar: false, //最顶部文字信息mobile: {menubar: true,plugins: ["autosave", "lists", "autolink"],toolbar: ["undo", "bold", "italic", "styleselect"],},// mode: "textareas",placeholder: "在此处书写...",// forced_root_block: '', // 删除在tinymce中自动添加的p标签// force_br_newlines : true,// force_p_newlines : false,preview_styles: "font-size color",invalid_styles: {'*': 'color font-size', //全局无效样式'a': 'background', // 链接禁用背景样式},plugins:"image link code codesample table lists wordcount autosave autolink insertdatetime preview media fullscreen quickbars print template", //就可以增加上面引入的插件,加入下面这一行就可以在toolbar栏显示相应插件。branding: false, //是否禁用“Powered by TinyMCE”toolbar: [{name: "history",items: ["undo", "redo"],},{name: "styles",items: ["styleselect"],},{name:'code',items:['codesample']},{name: "formatting",items: ["bold", "italic", "underline", "strikethrough"],},{name: "fonts",items: ["fontselect", "fontsizeselect", ],},{name: "colors",items: ["forecolor", "backcolor"],},{name: "media&link",items: ["link", "image", "media"],},{name: "alignment",items: ["alignleft", "aligncenter", "alignright", "alignjustify"],},{name: "indentation",items: ["outdent", "indent"],},{name: "blockquote",items: ["blockquote"],},{name: "table",items: ["table"],},{name: "lists",items: ["numlist", "bullist"],},{name: "tools",items: ["preview", 'print', "fullscreen"],},],//toolbar: "undo redo | fontselect fontsizeselect link autolink lineheight | forecolor backcolor | bold italic underline strikethrough | alignleft aligncenter alignright alignjustify | image imagetools | code | h1 h2 h3 h4 h5 blockquote table numlist bullist outdent indent preview fullscreen", //工具栏// toolbar_groups: {//     formatting: {//     icon: 'bold',//     tooltip: 'Formatting',//     items: 'bold italic underline | superscript subscript'//     }// },toolbar_mode: "sliding",//toolbar_sticky: true,image_caption: true,images_upload_handler: (blobInfo, success, failure, progress) => {this.uploadFile(blobInfo, success, failure);},//file_picker_callback: "",fontsize_formats:"8px 10px 12px 14px 16px 18px 24px 36px 48px 56px 72px",font_formats:"微软雅黑=Microsoft YaHei,Helvetica Neue,PingFang SC,sans-serif;苹果苹方=PingFang SC,Microsoft YaHei,sans-serif;宋体=simsun,serif;仿宋体=FangSong,serif;黑体=SimHei,sans-serif;Arial=arial,helvetica,sans-serif;Arial Black=arial black,avant garde;Book Antiqua=book antiqua,palatino;",// lineheight_formats: '1 1.1 1.2 1.3 1.4 1.5 2',// link_list: [// { title: '预置链接1', value: 'http://www.tinymce.com' },// { title: '预置链接2', value: 'http://tinymce.ax-z.cn' }// ],// image_list: [// { title: '预置图片1', value: 'https://www.tiny.cloud/images/glyph-tinymce@2x.png' },// { title: '预置图片2', value: 'https://www.baidu.com/img/bd_logo1.png' }// ],// image_class_list: [// { title: 'None', value: '' }// // { title: 'Some class', value: 'class-name' }// ],tabfocus_elements: "tinymce",importcss_append: true,textpattern_patterns: [{ start: "*", end: "*", format: "italic" },{ start: "", end: "", format: "bold" },{ start: "#", format: "h1" },{ start: "##", format: "h2" },{ start: "", format: "h3" },{ start: "#", format: "h4" },{ start: "##", format: "h5" },{ start: "", format: "h6" },{ start: "1. ", cmd: "InsertOrderedList" },{ start: "* ", cmd: "InsertUnorderedList" },{ start: "- ", cmd: "InsertUnorderedList" },],setup: (editor) => {// 自定义toolbar按钮,需要在toolbar添加editor.ui.registry.addButton('testBtn', {text: `按钮文字`,tooltip: '按钮提示',onAction: () => editor.insertContent('<a href="https://www.geekplus.xyz" target="_blank">test text</a>')})},},};},//   init: {//     setup: (Editor) => {//       // 初次化编辑器//       Editor.on("init", () => {//         Editor.setContent(this.value);//       });//     },//   },watch: {value(newVal) {//this.content = newValue;//用户vue绑定回显//if (this.isInit) {//this.isInit = false;//this.getContent();//   this.$nextTick(() => {//     const editor = tinymce.get("tinymce");//     editor.activeEditor.getContent()//     editor.setContent(newVal);//   });//}this.content=newVal;},content(newValue) {this.$emit("input", newValue);console.log(newValue);}},//获取焦点光标到最后面keepLastIndex (obj, window) {if (window.getSelection) { //ie11 10 9 ff safariobj.focus(); //解决ff不获取焦点无法定位问题var range = window.getSelection(); //创建rangerange.selectAllChildren(obj); //range 选择obj下所有子内容range.collapseToEnd(); //光标移至最后} else if (document.selection) { //ie10 9 8 7 6 5var range = document.selection.createRange(); //创建选择对象range.moveToElementText(obj); //range定位到objrange.collapse(false); //光标移至最后range.select();}}mounted() {tinymce.init({});this.$nextTick(() => {var ifra = document.getElementById("tinymce_ifr");//   this.keepLastIndex(//     ifra.contentWindow.document.getElementById("tinymce")//   );});},methods: {// file_picker_callback: function(callback, value, meta) {//     // Provide file and text for the link dialog//     if (meta.filetype == 'file') {//         callback('mypage.html', {text: 'My text'});//     }//     // Provide image and alt text for the image dialog//     if (meta.filetype == 'image') {//         callback('myimage.jpg', {alt: 'My alt text'});//     }//     // Provide alternative source and posted for the media dialog//     if (meta.filetype == 'media') {//         callback('movie.mp4', {source2: 'alt.ogg', poster: 'image.jpg'});//     }// },getContent(){var cnt = tinymce.editors['tinymce'].getContent();//console.log(cnt);},//自定义上传函数uploadFile(blobInfo, success, failure, progress) {let formData = new FormData();formData.append("file", blobInfo.blob());uploadImageFile(formData).then((response) => {//console.log(response);var serverUrl = response.url;let uploadSuccess = {};const imageUrl ="https://www.geekplus.xyz" + this.baseApi + serverUrl;// this.$message({//   message: "上传" + response.msg,//   type: "success",// });//success函数获取我们反悔的图片url,就实现了插入编辑器了success(imageUrl);// this.content += urluploadSuccess = { filePath: serverUrl };this.allImageList.push(uploadSuccess);}).catch((error) => {//console.log(error);failure("Invalid JSON: " + error.msg);this.$message({message: error.msg,type: "error",showClose: true,});});},},destroyed() {},
};
</script>
<style>
</style>

4.组件使用

<tiny-editor v-model="form.articleContent" @onSelectionChange="onEditorBlur($event)">
</tiny-editor>
import TinyEditor from "@/components/TinyMCE"
components: { TinyEditor },