vue3集成tinymce

1,602 阅读2分钟

简介

看了一圈富文本编辑器,发现quilltinymce比较符合自己的需求,功能上tinymce更加丰富、简单一些。

吐槽

吐槽一下tinymce的官网,给了@tinymce/tinymce-vue这个组件包,但是没想到就只是简单包装了一下(期初以为下载完这个包,引入vue组件内就完成了!),没想到如果只是单独引入这个包,是需要Api-key的,而且是云托管方式去下载tinymce,导致反复看官网折腾了好久!

自托管集成方式

有两种方式,一种是使用包管理工具、另一种是zip包。这里采用zip包的方式,因为tinymce还是挺大的,开发和打包过程影响编译时间。

以下面技术栈为例:

  1. 安装@tinymce/tinymce-vue
  2. 项目外面自己创建一个文件夹,npm init -y,然后npm i tinymce,安装完成后去node_modules内复制tinymcevue项目的public文件夹
  3. 在官网下载tinymce语言包,language。也放到public/tinymce文件夹内
  4. 创建编辑器组件,比如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>

效果图

image.png

注意的点

1. 如果是弹框内使用

需要注意设置.tox-tinymce-auxz-index大于2500,默认优先级会被element-plus的弹框盖住导致看不到tinymce toolbar的下拉菜单

相关文档

tinymce集成vue文档

tinymce全开源插件功能展示