简介
看了一圈富文本编辑器,发现quill和tinymce比较符合自己的需求,功能上tinymce更加丰富、简单一些。
吐槽
吐槽一下tinymce的官网,给了@tinymce/tinymce-vue这个组件包,但是没想到就只是简单包装了一下(期初以为下载完这个包,引入vue组件内就完成了!),没想到如果只是单独引入这个包,是需要Api-key的,而且是云托管方式去下载tinymce,导致反复看官网折腾了好久!
自托管集成方式
有两种方式,一种是使用包管理工具、另一种是zip包。这里采用zip包的方式,因为tinymce还是挺大的,开发和打包过程影响编译时间。
以下面技术栈为例:
- 管理台框架 - pure-admin-thin
- vite@5 + vue3 + Ts
- 安装
@tinymce/tinymce-vue - 项目外面自己创建一个文件夹,
npm init -y,然后npm i tinymce,安装完成后去node_modules内复制tinymce到vue项目的public文件夹 - 在官网下载
tinymce语言包,language。也放到public/tinymce文件夹内 - 创建编辑器组件,比如
TinyEditor.vue,代码配置如下:
可选:因为是编译后的zip包是没有TS类型提示的,为了TS类型提示,安装pnpm add tinymce -D。
// TinyEditor.vue
<script setup lang="ts">
import { onBeforeUnmount, ref, shallowRef, onMounted } from "vue";
import Editor from "@tinymce/tinymce-vue";
import { apiAttachmentCreate } from "@/api-custom/base";
import type { EditorOptions, RawEditorOptions } from "tinymce";
defineOptions({
name: "BaseEditor"
});
// 图片上传自定义逻辑
/** 文档:https://www.tiny.cloud/docs/tinymce/latest/upload-images/ */
type UploadFn = RawEditorOptions["images_upload_handler"];
const imageUploadHandler: UploadFn = async function (blobInfo, progress) {
const formData = new FormData();
formData.append("image", blobInfo.blob());
const res = await apiAttachmentCreate(formData);
return res.url;
};
// 双向绑定v-model
const modelContent = defineModel({ default: "" });
// 初始化配置
const initConfig = ref<RawEditorOptions>({
// 如果不设置license_key为gpl,console会一直提示一个模式问题
license_key: "gpl",
// 编辑器的高度
height: 300,
// 移除tinymce右上角升级提示
promotion: false,
// 移除tinymce右下角品牌提示
branding: false,
// 设置语言包路径
language_url: "/tinymce/langs/zh_CN.js",
// 设置语言
language: "zh_CN",
// 配置插件列表
plugins:
"preview importcss searchreplace autolink save directionality code visualblocks visualchars fullscreen image link media codesample table charmap pagebreak nonbreaking anchor insertdatetime advlist lists wordcount help charmap quickbars emoticons accordion",
// 配置工具栏
toolbar: [
"undo redo | blocks fontfamily fontsize | link image | table media | code fullscreen preview",
"bold italic underline strikethrough | lineheight align numlist bullist | forecolor backcolor removeformat | charmap emoticons codesample"
],
// 内容默认样式
content_style:
"body { font-family:Helvetica,Arial,sans-serif; font-size:14px }",
// 配置图片上传功能
images_upload_handler: imageUploadHandler
});
</script>
<template>
<Editor
:init="initConfig"
tinymceScriptSrc="/tinymce/tinymce.js"
v-model="modelContent"
/>
</template>
<style>
.tox-tinymce {
border: none !important;
}
/* TODO: 因为Element plus的dialog默认是2000以上的hz-index,会遮住tinymce的弹框 */
.tox-tinymce-aux {
z-index: 3001 !important;
}
</style>
效果图
注意的点
1. 如果是弹框内使用
需要注意设置.tox-tinymce-aux的z-index大于2500,默认优先级会被element-plus的弹框盖住导致看不到tinymce toolbar的下拉菜单