- 作为踩坑过 vue-quill-editor 富文本编辑器,以及 wangEditor 编辑器来说,个人感觉还是 Tinymce 功能更加强大跟齐全一些。说一下体验感,wangEditor 编辑器太年轻了,功能上缺乏很多东西,比如说上传图片无法方便的添加图片的 alt 信息,git issue上也有人提意见,功能目前还在计划中。而 vue-quill-editor 这款编辑器是根据 quill 编辑器为基础做的二次加工,功能上来说,感觉没有 Tinymce 增加功能方便简洁,而且为了一些特定化需求,可能还需要更改源码文件,这样就导致如果有人删了一下依赖包重新下载就凉透了。从目前来看,还是 Tinymce 这款功能比较齐全,而且也有人专门翻译做了中文文档,Tinymce 中文文档传送门,这个人做的还不错,更新速度也可以,在首页下方也有功能完全的Demo 可以体验。
- 接下来,开始说我在vue中 使用体验了,首先如果 Tinymce 第三方集成区所集成的版本所容纳的功能足够的话,就可以不用按照我的方法,可以直接使用 vue-tinymce 这个集成方案来解决,但是我为了追求所有的功能都能跟上最新版,所以没有选择这个方案,而是用了这个方案
npm install --save @tinymce/tinymce-vue@3.2.8 tinymce
- 注意 @tinymce/tinymce-vue@3.2.8 指定版本安装,因为从 4.x.x 版本开始就是 vue3 所支持的版本,如果是 vue2 就必须装 4.x.x 版本以下的,否则会报错。
- 安装好之后,自定义一个编辑器组件,比如:
<template>
<div class="tinymce-editor">
<editor
v-model="myValue"
:disabled="disabled"
@onClick="onClick"
:init="init"
/>
</div>
</template>
<script>
import { getToken } from "@/utils/auth";
import tinymce from "tinymce/tinymce";
import Editor from "@tinymce/tinymce-vue";
import "tinymce/themes/silver";
import "tinymce/icons/default/icons"; //解决了icons.js 报错Unexpected token '<'
// 编辑器插件plugins
// 更多插件参考:https://www.tiny.cloud/docs/plugins/
import "tinymce/plugins/image"; // 插入上传图片插件
import "tinymce/plugins/media"; // 插入视频插件
import "tinymce/plugins/table"; // 插入表格插件c
import "tinymce/plugins/lists"; // 列表插件
import "tinymce/plugins/wordcount"; // 字数统计插件
import "tinymce/plugins/charmap"; // 特殊字符
import "tinymce/plugins/preview"; // 预览
import "tinymce/plugins/hr"; // 水平线
import "tinymce/plugins/help"; // 帮助文档
import "tinymce/plugins/imagetools"; // 图片编辑工具
import "tinymce/plugins/code"; // 编辑源码
import "tinymce/plugins/fullscreen"; // 全屏
import "tinymce/plugins/link"; // 超链接
import "tinymce/plugins/paste"; // 粘贴
import "tinymce/plugins/quickbars"; // 快速工具栏
import "tinymce/plugins/searchreplace"; // 查找替换
export default {
components: {
Editor,
},
props: {
value: {
type: String,
default: "",
},
// 基本路径,默认为空根目录,如果你的项目发布后的地址为目录形式,
// 即abc.com/tinymce,baseUrl需要配置成tinymce,不然发布后资源会找不到
baseUrl: {
type: String,
default: "",
},
disabled: {
type: Boolean,
default: false,
},
plugins: {
type: [String, Array],
default:
"lists image imagetools media table wordcount charmap preview hr help code fullscreen link paste quickbars searchreplace ",
},
toolbar: {
type: [String, Array],
default() {
return [
"code preview hr help searchreplace | removeformat charmap paste | fullscreen",
"undo redo | formatselect | fontsizeselect | fontselect | bold italic underline forecolor backcolor | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link lists image imagetools media table |",
];
},
},
},
data() {
return {
init: {
skin_url: "/tinymce/skins/ui/oxide",
language: "zh_CN",
language_url: "/tinymce/langs/zh_CN.js",
protect: [
/\<\/?(if|endif)\>/g, //<if> & </endif>
/\<xsl\:[^>]+\>/g, //<xsl:...>
/<\?php.*?\?>/g, //php代码
], // 代码保护
height: 700,
plugins: this.plugins,
toolbar: this.toolbar,
charmap_append: [
[0x2615, "morning coffee"],
[0x2600, "sun"],
[0x2601, "cloud"],
],
branding: false,
menubar: false,
// 此处为图片上传处理函数,这个直接用了base64的图片形式上传图片,
// 如需ajax上传可参考https://www.tiny.cloud/docs/configure/file-image-upload/#images_upload_handler
images_upload_handler: (blobInfo, success, failure, progress) => {
var xhr, formData;
xhr = new XMLHttpRequest();
xhr.withCredentials = false;
xhr.open("POST", `${process.env.VUE_APP_BASE_API}/common/upload`);
xhr.setRequestHeader("Authorization", `Bearer ${getToken()}`);
xhr.upload.onprogress = function (e) {
progress((e.loaded / e.total) * 100);
};
xhr.onload = function () {
var json;
if (xhr.status == 403) {
failure("HTTP Error: " + xhr.status, { remove: true });
return;
}
if (xhr.status < 200 || xhr.status >= 300) {
failure("HTTP Error: " + xhr.status);
return;
}
json = JSON.parse(xhr.responseText);
if (!json || typeof json.url != "string") {
failure("Invalid JSON: " + xhr.responseText);
return;
}
success(json.url);
};
xhr.onerror = function () {
failure(
"Image upload failed due to a XHR Transport error. Code: " +
xhr.status
);
};
formData = new FormData();
formData.append("file", blobInfo.blob(), blobInfo.filename());
xhr.send(formData);
},
},
myValue: this.value,
};
},
mounted() {
tinymce.init({});
},
methods: {
// 添加相关的事件,可用的事件参照文档=> https://github.com/tinymce/tinymce-vue => All available events
// 需要什么事件可以自己增加
onClick(e) {
this.$emit("onClick", e, tinymce);
},
// 可以添加一些自己的自定义事件,如清空内容
clear() {
this.myValue = "";
},
},
watch: {
value(newValue) {
this.myValue = newValue;
},
myValue(newValue) {
this.$emit("input", newValue);
},
},
};
</script>
- 注意,我这里只引入了一些插件,如果想要其他的工具,比如图片的插件,就需要先引入插件
// 编辑器插件plugins
import "tinymce/plugins/image"; // 插入上传图片插件
// 然后需要在 plugins toolbar 中放入插件
plugins:"image";
toolbar:"image"
- 关键一点,就是如果看不到编辑器显示出来,还需要一步,在
node_modules
中找到 tinymce,找到对应skins
文件,在public
文件夹下创建一个tinymce
文件夹,将其复制出来放在public/tinymce
文件夹下,或者 放在你可以知道准确的引入地址文件夹下的xxxx/tinymce
文件夹中。init
时需要设置skin_url
,这是线下环境,如果线上环境找不到路径,就需要配置一个baseUrl
// 基本路径,默认为空根目录,如果你的项目发布后的地址为目录形式,
// 即abc.com/tinymce,baseUrl需要配置成tinymce,不然发布后资源会找不到
skin_url: "/tinymce/skins/ui/oxide",
// or
skin_url: `${baseUrl}/tinymce/skins/ui/oxide`,
- 如果看不懂英文,可以配置中文资源包,先去本地化资源包下载地址 下载,可以简单注册一个账号,然后进入文档 - > 本地化配置,就可以看到这个页面了,或者复制我从官网下载过来的中文包也行;
8. 我目前所用的本地化中文资源包js 文件
9. 然后在之前创建的的 tinymce
文件夹中再创建一个 language
文件夹,将 zh_CN.js
文件放在 language
中,然后在 init
中引入
language: "zh_CN",
language_url: "/tinymce/langs/zh_CN.js",
// or
language_url: `${baseUrl}/tinymce/langs/zh_CN.js`,
- 接下来就可以去其他文件引用这个编辑器组件了。如果有其他的坑可以联系我,大家一起讨论。如果没看到,可以+qq 1499224990 联系我