vue3使用Tinymce编辑器

 首先去官网获取免费的key 获取地址,需要注册登录。 获取后还须将使用该编辑器的域名添加到 这里,默认有只有localhost。

 在项目中获取依赖 npm install "@tinymce/tinymce-vue" 

 在页面或组件中引用  import Editor from "@tinymce/tinymce-vue";

 封装成组件

<template>
<div class="tinymce-editor">
<Editor
apiKey="获取的key"
:init="editorInit"
:value="contentValue"
/>
</div>
</template>
<script setup>
import { ref, watch, shallowRef } from "vue";
import Editor from "@tinymce/tinymce-vue";

const props = defineProps({
  modelValue: {
    type: String,
    default: "",
  },
  height: {
    type: Number,
    default: 500,
  },
  plugins: {
    type: [String, Array],
    default: "preview image link media table help",
  },
  toolbar: {
    type: [String, Array],
    default:
      "undo redo | bold italic underline strikethrough | fontselect fontsizeselect formatselect | image media link | alignleft aligncenter alignright alignjustify | numlist bullist | forecolor backcolor removeformat | charmap emoticons | fullscreen preview save",
  },
});

const emit = defineEmits(["update:modelValue", "change", "blur"]);
const contentValue = ref(props.modelValue);
const editorInstance = ref(null);
const showEditor = ref(false);
// 编辑器初始化配置
const editorInit = {
  language: "zh-CN",
  height: props.height,
  plugins: props.plugins,
  toolbar: props.toolbar,
  branding: false,
  promotion: false,
  elementpath: false,
  content_style: "body {font-size: 14px }",
  skin: "oxide",
  icons: "default",
  toolbar_mode: "wrap",
  contextmenu: "link image table",
  powerpaste_word_import: "clean",
  powerpaste_html_import: "clean",
  paste_data_images: true,
  images_upload_handler: handleImageUpload,
  file_picker_callback: handleFilePicker,
  setup: (editor) => {
    console.log("editor:", editor);
    editorInstance.value = editor;
    editor.on("init", () => {
      // 设置初始内容
      showEditor.value = true;
      if (props.modelValue) {
        editor.setContent(props.modelValue);
      }
    });
    // 监听内容变化事件
    editor.on("input", () => {
      const content = editor.getContent();
      console.log("input:", content);
      contentValue.value = content;
      emit("update:modelValue", content);
    });

    // 监听内容变化事件(更全面)
    editor.on("change", () => {
      const content = editor.getContent();
      console.log("内容变化:", content);
      contentValue.value = content;
      emit("update:modelValue", content);
    });
  },
};


// 处理图片上传
function handleImageUpload(blobInfo, progress) {
  return new Promise((resolve, reject) => {
    // 将 blob 转换为 File 对象
    const file = new File([blobInfo.blob()], blobInfo.filename(), {
      type: blobInfo.blob().type,
    });
    console.log("上传图片:", file);
    
  });
}
// 处理视频上传
function handleFilePicker(callback, value, meta) {
  if (meta.filetype === "media") {
    // 视频上传逻辑
    const input = document.createElement("input");
    input.type = "file";
    input.accept = "video/*";
    input.onchange = (e) => {
      const file = e.target.files[0];
      // 上传视频到服务器
    };
    input.click();
  }
}
// 初始化 TinyMCE
const editorRef = shallowRef();
// 监听外部值变化
watch(
  () => props.modelValue,
  (val) => {
    if (val !== contentValue.value) {
      console.log("外部值变化:", val);
      contentValue.value = val || "";
      console.log(editorInstance.value, "editorInstance");
      if (editorInstance.value) {
        editorInstance.value.setContent(val || "");
      }
    }
  }
);

defineExpose({
  editorRef,
});
</script>
 
父组件中引用
<Editor
   :modelValue="content"
   @update:modelValue="editorChange"
/>


import Editor from "@/components/Editor.vue";
const content = ref('');
const editorChange = (val) => {
  console.log(val, "val");
};
 
代码中有上传图片和视频的方法,只用在对应代码位置写上传到服务器逻辑即可。
若遇到编辑器弹框被Element Plus弹框盖住的情况,可在app.vue中设置 
.tox {
 z-index: 3050 !important;
}
 
 
posted @ 2025-12-23 15:07  yanghaogogogo  阅读(0)  评论(0)    收藏  举报