Vue3——Tinymce6富文本编辑器的使用方法

TinyMCE 6 是一款功能强大且灵活的富文本编辑器,可以嵌入到 Web 应用程序中。

一、安装

本文的讲解主要以tinymce6 版本为例

 官网地址   Migrating from TinyMCE 5 to TinyMCE 6 | TinyMCE Documentation

要将 TinyMCE 添加到项目中,请执行以下操作:

  • 使用 npm,在命令行上运行以下命令:

npm install tinymce

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

  • 使用 Yarn,在命令行上运行以下命令:
yarn add t inymce@^6
 

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

二、初始化配置

import tinymce from "tinymce/tinymce";
import "tinymce/models/dom"; // 特别注意 tinymce 6.0.0 版本之后必须引入,否则不显示
import "tinymce/themes/silver/theme";
import Editor from "@tinymce/tinymce-vue"; // 引入组件
//引入工具栏图标和主题
import "tinymce/icons/default/icons";
import "tinymce/themes/silver";
// 引入富文本编辑器主题的js和css,不然显示出错
import "tinymce/themes/silver/theme.min";
import "tinymce/skins/ui/oxide/skin.min.css";

// 都是富文本插件
import "tinymce/icons/default";
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/plugins/autosave"; //自动保存
import "tinymce/plugins/save"; //保存
// import "tinymce/plugins/preview"; //预览
// 以上所有的样式在 node_modules 下面 tinymce 里面的 plugins 都能找到。
const init = {
  //初始化数据
  resize: false, //是否可自主拉伸
  promotion: false, //Upgrade是否开启
  statusbar: false, //状态栏是否显示
  content_style: "body{margin:0;outline:none;font-family:'宋体';};",
  language_url: "/langs/zh-Hans.js", // 引入语言包(该语言包在public下,注意文件名称)
  language: "zh-Hans", // 这里名称根据 zh-Hans.js 里面写的名称而定
  skin_url: "/skins/ui/oxide", // 这里引入的样式
  plugins: "lists image code table wordcount   autosave save", // 富文本插件
  toolbar:
    "| undo redo | fontfamily fontsize | italic bold underline strikethrough forecolor |  alignleft alignright aligncenter alignjustify  indent outdent  lineheight numlist  save",
  branding: false, //是否禁用“Powered by TinyMCE”
  menubar: false, //顶部菜单栏显示
  font_size_formats: "11pt 12pt 14pt 16pt 18pt 24pt 36pt",
  font_family_formats:
    "微软雅黑='微软雅黑';宋体='宋体';黑体='黑体';仿宋='仿宋';楷体='楷体';隶书='隶书';幼圆='幼圆';Andale Mono=andale mono,times;Arial=arial,helvetica,sans-serif;Arial Black=arial black,avant garde;Book Antiqua=book antiqua,palatino;Comic Sans MS=comic sans ms,sans-serif;Courier New=courier new,courier;Georgia=georgia,palatino;Helvetica=helvetica;Impact=impact,chicago;Symbol=symbol;",
  // paste_convert_word_fake_lists: false, // 插入word文档需要该属性
  content_css: "/skins/content/default/content.css", //以css文件方式自定义可编辑区域的css样式,css文件需自己创建并引入
  images_upload_handler: (blobInfo, success, failure) => {
    // console.log(blobInfo.blob());
    // 上传图片需要,FormData 格式的文件;
    const formDataUp = new FormData();
    // img  是接口需要的上传的属性名,一般属性名是 file
    formDataUp.append("img", blobInfo.blob());
    // // console.log(formDataUp);
    axios.post("xxxx", formDataUp).then((res) => {
      success("返回的上传图片后的地址");
    });
  },
  inline: true,
  // 将工具栏固定在顶部且blur时工具栏不会隐藏
  fixed_toolbar_container: "#myToolbar",
  // 此选项允许提供将在每次初始化编辑器实例时执行的函数。
  init_instance_callback: function (editor) {
    editor.fire("focus");
    // 解决部署到生产环境时setContent 有可能会失效的问题
    if (editor != null) {
      getDetails();
    }
  },
  setup: function (editor) {
    // console.log(editor, "^^^^^^^^^");
    editor.on("blur", function () {
      return false;
    });
    // 禁止ctrl+c  ctrl+v 复制
    editor.on("keydown", function (e) {
      if ((e.ctrlKey || e.metaKey) && e.key === "c") {
        console.log(canCopy.value, "是否支付");
        if (!canCopy.value) {
          e.preventDefault();
        }
      }
    });

    // 监听编辑器撤销事件
    editor.on("undo", function () {
      console.log("当前正在执行撤销操作");
      // 判断内容区是否为空
      if (editor.getContent() === "") {
        // 内容区为空,重新获取数据
        console.log("内容区为空");
        getDetails();
      } else {
        // 内容区不为空
        console.log("内容区不为空");
      }
    });
    // 编辑器内容发生变化时
    editor.on("change", function () {
      console.log("内容区发生变化");
      let obj = {};
      obj.hcn = document.getElementById("tinymce").innerHTML;
      obj.di = di.value;
      obj.index = -1;
      if (!notUpdateHtml.value) {
        updateHtmlContent({ ...obj }).then((res) => {
          nextTick(() => {
            MathJax.typesetPromise();
          });
        });
      }
    });
  },
  // 允许在 UI 中指定缩进/缩进按钮的缩进级别。
  indentation: "2rem",
  // 如果编辑器在缩进内容时应使用边距而不是填充,则设置此选项。
  indent_use_margin: false,
  // 自动保存时间间隔
  autosave_interval: "5s",
  // 自动草稿的有效期
  autosave_retention: "20m",
  // 当编辑器初始化时内容区为空时,Tinymce是否应自动还原存储在本地存储中的草稿
  autosave_restore_when_empty: false,
  // 当内容无变化时禁用保存按钮
  save_enablewhendirty: false,
  save_onsavecallback: function () {
    ElMessage({
      showClose: true,
      message: "保存成功!",
      type: "success",
    });
  },
  // 粘贴过程中触发的事件
  paste_preprocess: function (plugin, args) {
    // 不可粘贴
    // args.content = "";
  },
};
onMounted(() => {
  tinymce.init({}); // 初始化富文本
});

页面中使用

api-key 可以到官网去申请,以免可能会出现使用的过程中提示申请api-key的情况

 <editor
              style="margin-top: -25px"
              id="tinymce"
              api-key=""
              :init="init"
            ></editor>

三、常见踩坑点

1.改变工具栏和编辑区默认上下的模式,将工具栏固定在某个容器中

inline: true,
  // 将工具栏固定在顶部且blur时工具栏不会隐藏
  fixed_toolbar_container: "#myToolbar",

2.如何将数组渲染至内容区中——使用tinymce中的setContent

使用凭借html的形式,然后使用tinymce中的setContent方法将数据渲染至内容区中

3.如何禁止复制内容区中的内容

setup: function (editor) {
    // console.log(editor, "^^^^^^^^^");
    editor.on("blur", function () {
      return false;
    });
    // 禁止ctrl+c  ctrl+v 复制
    editor.on("keydown", function (e) {
      if ((e.ctrlKey || e.metaKey) && (e.key === "c" || e.key === "v")) {
        e.preventDefault(); // 阻止 Ctrl+C 和 Ctrl+V 的默认行为
      }
    });
  },
若需要实现右击菜单栏的形式实现监听复制事件,可以通过监听编辑器的 复制 事件
editor.on("copy", function (e) {
      if (!canCopy.value) {
        e.preventDefault();
      }
    });

4.删除TinyMCE-6编辑器周围的蓝线-内联模式

<style>
  * [contentEditable="true"]:focus
  { outline: 0px ; }
</style>

5.防止撤回到最初,内容区的内容消失

多次撤回后内容区的内容会为空,此时可以通过监听编辑器内容是否在执行撤销操作,如果进行撤销,通过tinymce中getContent的内容是否为空,为空则重新执行你获取数据的方法即可

(至于为何撤回时导致内容区的内容丢失,暂时还未找到原因,如有知晓如何解决,欢迎在评论区留言!)

6.实现设置字体选项默认为宋体

7.解决setContent有可能会失效的问题

// 此选项允许提供将在每次初始化编辑器实例时执行的函数。
  init_instance_callback: function (editor) {
    editor.fire("focus");
    // 解决部署到生产环境时setContent 有可能会失效的问题
    if (editor != null) {
      getDetails();
    }
  },

8.tinymcea6 以上版本去除换行增加的p标签

9.如果当前有未保存的更改,关闭提示窗口

10.关于插入表格,给页面增添了多余的p标签,且原本的p标签丢失id

1.直接插入表格——table作为独立的块元素,原本的p标签挪到了table的后面,且table前面新增了一个p标签,并缺少了之前的id

2.enter插入表格——table作为独立的块元素,原本的p标签丢失了id

解决:通过监听内容区的点击事件,记录当前光标所在的 dom 节点 id(curHtmlId),如果table之前的p没有id,就为其添加curHtmlId,随后把没有innerText的p节点移除,以免造成页面重复id

editor.on("click", function (e) {
      // 获取当前鼠标光标所在的 DOM 元素 id
      const currentNode = editor.selection.getNode();
      curHtmlId.value = currentNode.id;
      console.log(curHtmlId.value, "############");
    });

// 编辑器内容发生变化时
    editor.on("change", function () {
      setTimeout(() => {
        console.log("内容区发生变化");
        document.querySelectorAll("#tinymce p").forEach((p) => {
          if (isIdeo.value == 0) {
            p.style.backgroundColor = "white";
          }
        });


        //处理表格
        // 1.enter插入表格后,table作为独立的块元素,原本的p标签丢失了id
        // 2.直接插入表格——table作为独立的块元素,原本的p标签挪到了table的后面,且table前面新增了一个p标签,并缺少了之前的id
        const tables = document.querySelectorAll("table");


        tables.forEach((table) => {
          // 获取 table 前一个 p 标签
          const prevP = table.previousElementSibling;
          // 获取 table 后一个 p 标签
          const nextP = table.nextElementSibling;


          // 检查前后兄弟元素是否为 p 标签
          if (
            prevP &&
            prevP.tagName.toLowerCase() === "p" &&
            nextP &&
            nextP.tagName.toLowerCase() === "p"
          ) {
            if (!prevP.id) {
              prevP.id = curHtmlId.value;
            }
          }
        });
        const ps = document.querySelectorAll("p");
        ps.forEach((item) => {
          if (item.tagName.toLowerCase() === "p") {
            if (!item.innerText) {
              item.remove();
            }
          }
        });


        let obj = {};
        obj.hcn = document.getElementById("tinymce").innerHTML;
        obj.di = di.value;
        obj.index = "-1";
        if (!notUpdateHtml.value) {
          updateHtmlContent({ ...obj }).then((res) => {
            // if (res.code == "00000") {
            //   hasHtml.value = true;
            //   tinymceEditorRef.value = tinymce.EditorManager.get("tinymce");
            //   tinymceEditorRef.value.setContent(res.obj);
            // }
          });
        }
      }, 300);
    });

  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Vue3中使用Tinymce富文本编辑器,你可以按照以下步骤进行操作: 1. 首先,确保你已经安装了TinymceTinymce-Vue的相关包。你可以通过运行以下命令来安装Tinymce-Vue版本3: ``` npm install --save @tinymce/tinymce-vue@^3 ``` 2. 在你的Vue组件中,引入Tinymce-Vue组件: ```javascript import { Editor } from '@tinymce/tinymce-vue'; ``` 3. 在你的模板中,使用Tinymce-Vue组件: ```html <template> <div> <editor v-model="content" :init="editorConfig"></editor> </div> </template> ``` 4. 在你的Vue组件中,定义Tinymce的配置项: ```javascript export default { data() { return { content: '', editorConfig: { // 在这里配置Tinymce的选项 } }; } } ``` 5. 根据你的需求,配置Tinymce的选项。你可以参考Tinymce的官方文档和中文文档来了解所有可用的选项。你也可以参考Tinymce-Vue在GitHub上的项目来获取更多示例和用法。 请注意,Tinymce-Vue版本4支持Vue3.0,而不支持Vue2.0。如果你的项目是Vue2.0,你需要安装Tinymce-Vue版本3。 希望这些信息对你有帮助!如果你需要更多的参考文档,你可以访问Tinymce的官方网站和中文文档,以及Tinymce-Vue在GitHub上的项目。 #### 引用[.reference_title] - *1* *2* *3* [在vue3.0项目中使用tinymce富文本编辑器](https://blog.csdn.net/mrjimin/article/details/121648927)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值