Tinymce富文本编辑器在vue项目中的使用;引入第三方插件和上传视频、图片等

先放张效果图

第一步:安装依赖 npm install tinymce@5.0.12

第二步:在项目中的public文件夹中新建tinymce文件夹(因为我的项目是脚手架创建的,所以公共文件夹是public);在node_modules中找到skins文件夹复制到tinymce文件夹中

第三步:因为tinymce是英文版本的,所以要下载汉化包中文js,放到上面的tinymce文件夹中

下载网址:https://www.tiny.cloud/get-tiny/language-packages/

翻到最底部,找到中文语言点击Download按钮,放到和上一步的skins文件夹同级目录的tinymce文件夹中

第四步:封装tinymce组件,这里就直接上代码了;

Tip: 1. <script>里面import的这些都是富文本编辑器的工具栏,需要什么就引入什么;

2. 运行项目可能会有引入的工具报错,针对报错的工具再npm install即可;

第三方插件的引入(数学公式、导入word):

1. 最后两行是另外下载的插件(数学公式、导入word),上面的二和三步的tinymce文件夹里面新建plugins文件夹,下载的两个插件就丢这里面;

数学公式: kityformula-editor 下载地址: http://tinymce.ax-z.cn/more-plugins/kityformula-editor.php

导入word:importword 下载地址:https://github.com/Five-great/tinymce-plugins

2.代码中的toolbar数组里面就是工具的名称;| 符号就是编辑器工具栏的分隔符,界面的工具摆放顺序就是根据代码中的工具摆放顺序

上传视频工具:

1. 编辑器初始化中的“file_picker_callback”方法里面写的是上传视频的内容

2. validateVideo 方法是在文件后面的方法中定义的,目的是验证上传的视频是否符合,验证通过定义了一个全局的遮罩loading,再调用定义的uploadFile方法,调用后台接口把视频源传到后台进行业务的交互,上传成功后必须要写这行代码才能将视频显示在富文本编辑器中:callback(域名 + 代理地址 + 后台返回的路径)

<template>
  <div class="tinymce-editor">
    <editor v-model="myValue" :init="init" :disabled="disabled" @onClick="onClick">
    </editor>
  </div>
</template>
<script>
import tinymce from "tinymce/tinymce";
import "tinymce/themes/silver/theme";
import Editor from "@tinymce/tinymce-vue";
// import "tinymce/icons/default/icons";
// import "tinymce/models/dom/model";
import "tinymce/plugins/print";
import "tinymce/plugins/preview";
import "tinymce/plugins/searchreplace";
import "tinymce/plugins/autolink";
import "tinymce/plugins/directionality";
import "tinymce/plugins/visualblocks";
import "tinymce/plugins/visualchars";
import "tinymce/plugins/fullscreen";
import "tinymce/plugins/image";
import "tinymce/plugins/link";
import "tinymce/plugins/media";
import "tinymce/plugins/template";
import "tinymce/plugins/code";
import "tinymce/plugins/codesample";
import "tinymce/plugins/table";
import "tinymce/plugins/charmap";
import "tinymce/plugins/hr";
import "tinymce/plugins/pagebreak";
import "tinymce/plugins/nonbreaking";
import "tinymce/plugins/anchor";
import "tinymce/plugins/insertdatetime";
import "tinymce/plugins/advlist";
import "tinymce/plugins/lists";
import "tinymce/plugins/wordcount";
import "tinymce/plugins/imagetools";
import "tinymce/plugins/textpattern";
import "tinymce/plugins/help";
import "tinymce/plugins/emoticons";
import "tinymce/plugins/autosave";
// import "tinymce/plugins/bdmap";
// import "tinymce/plugins/indent2em";
import "tinymce/plugins/autoresize";
// import "tinymce/plugins/formatpainter";
// import "tinymce/plugins/axupimgs";
import "../../../../../public/tinymce/plugins/kityformula-editor/plugin.min.js";
import "../../../../../public/tinymce/plugins/importword/plugin.min.js";
import { uploadvideo } from "@admin/api/Settings/Secureaccess/Onlinelearning";
export default {
  components: {
    Editor,
  },
  props: {
    //传入一个value,使组件支持v-model绑定
    value: {
      type: String,
      default: "",
    },
    disabled: {
      type: Boolean,
      default: false,
    },
    plugins: {
      type: [String, Array],
      // default: "lists image media table textcolor wordcount contextmenu",
      default:
        "print preview searchreplace autolink directionality visualblocks visualchars fullscreen image link media template code codesample table charmap hr pagebreak nonbreaking anchor insertdatetime advlist lists wordcount imagetools textpattern help emoticons autosave  autoresize kityformula-editor importword",
    },
    fontsize_formats: "12px 14px 16px 18px 24px 36px 48px 56px 72px",
    toolbar: {
      type: [String, Array],
      // default: "undo redo |  formatselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | lists image media table | removeformat",
      default:
        "code undo redo restoredraft | cut copy paste pastetext | forecolor backcolor bold italic underline strikethrough link anchor | alignleft aligncenter alignright alignjustify outdent indent | \
    styleselect formatselect fontselect fontsizeselect | bullist numlist | blockquote subscript superscript removeformat | \
    table image media charmap hr pagebreak insertdatetime print preview | fullscreen | bdmap indent2em lineheight formatpainter axupimgs | kityformula-editor importword",
    },
    fontFormats: {
      type: String,
      default:
        "微软雅黑=Microsoft YaHei,Helvetica Neue,PingFang SC,sans-serif;宋体=simsun, serif;苹果苹方=PingFang SC, Microsoft YaHei, sans- serif;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;Symbol = symbol;Tahoma = tahoma, arial, helvetica, sans - serif;Terminal = terminal, monaco;Times New Roman = times new roman, times;Verdana = verdana, geneva",
    },
  },
  data() {
    return {
      //初始化配置
      init: {
        language_url: "/tinymce/zh_CN.js",
        language: "zh_CN",
        height: 650,
        skin_url: "/tinymce/skins/ui/oxide",
        plugins: this.plugins,
        toolbar: this.toolbar,
        // branding: false,
        // menubar: true,
        // quickbars_selection_toolbar:
        //   "removeformat | bold italic underline strikethrough | fontsizeselect forecolor backcolor",
        font_formats: this.fontFormats,
        fontsize_formats: this.fontsize_formats,
        //此处为图片上传处理函数,这个直接用了base64的图片形式上传图片,
        //如需ajax上传可参考https://www.tiny.cloud/docs/configure/file-image-upload/#images_upload_handler
        images_upload_handler: (blobInfo, success, failure) => {
          const img = "data:image/jpeg;base64," + blobInfo.base64();
          success(img);
        },
        file_picker_types: "media",
        media_live_embeds: true,
        file_picker_callback: (callback, value, meta) => {
          if (meta.filetype === "media") {
            const input = document.createElement("input");
            input.setAttribute("type", "file");
            const that = this; // 为 Vue 构造函数中的 this,指向 Vue 实例对象
            input.onchange = async function () {
              const file = this.files[0]; // 为 HTMLInputElement 构造函数中的 this,指向 input 实例对象
              const isValid = await that.validateVideo(file);

              if (isValid) {
                const loading = that.$loading({
                  lock: true,
                  text: "Loading",
                  spinner: "el-icon-loading",
                  background: "rgba(0, 0, 0, 0.7)",
                });
                that.uploadFile(file, "video");
                setTimeout(() => {
                  loading.close();
                  if (that.videomsg.url != "") {
                    callback(that.location + "lab/" + that.videomsg.url);
                  }
                  // console.log(that.location + "lab/" + that.videomsg.url);
                }, 2000);
                // const { url } = await that.uploadFile(file, "video");
                // callback(url);
              } else {
                callback();
              }
            };

            input.click();
          }
        },
        // video_template_callback: (data) => {
        //   console.log(data);
        //   let source = that.location + "lab/" + data.source1;
        //   console.log(source);
        //   return `<video width="745" height="420" controls="controls" src=${data.source} />`;
        // },
      },
      myValue: "",
      videomsg: {
        url: "",
        name: "",
      },
      location: "http://" + window.location.host + "/",
    };
  },
  mounted() {
    tinymce.init({});
  },
  methods: {
    //添加相关的事件,可用的事件参照文档=> https://github.com/tinymce/tinymce-vue => All available events
    //需要什么事件可以自己增加
    onClick(e) {
      this.$emit("onClick", e, tinymce);
    },
    //可以添加一些自己的自定义事件,如清空内容
    clear() {
      this.myValue = "";
    },
    //校验视频格式和内存大小
    validateVideo(file) {
      const isMP4 = file.type === "video/mp4";
      const isLt3M = file.size / 1024 / 1024 < 5;

      if (!isMP4) {
        this.$message.error("上传视频必须为 MP4 格式!");

        return false;
      }

      if (!isLt3M) {
        this.$message.error("上传视频大小限制 5M 以内!");

        return false;
      }

      const duration = this.getVideoDuration(file);
      if (duration > 60) {
        this.$message.error("上传视频时长不能超过 60 秒!");

        return false;
      }

      return true;
    },
    //获取视频源
    getVideoDuration(file) {
      return new Promise((resolve) => {
        const videoElement = document.createElement("video");
        videoElement.src = URL.createObjectURL(file);

        videoElement.addEventListener("loadedmetadata", () => {
          resolve(videoElement.duration);
        });
      });
    },
    //上传视频
    uploadFile(file, folder = "images") {
      const formData = new FormData();
      formData.append("file", file);
      uploadvideo(formData).then((res) => {
        if (res.code == 0) {
          this.videomsg.url = res.data;
          this.videomsg.name = file.name;
          // return {
          //   url: res.data,
          //   name: file.name,
          // };
        } else {
          this.$message({
            message: res.message,
            type: "error",
            duration: "5000",
          });
        }
      });
    },
  },
  watch: {
    value(newValue) {
      this.myValue = newValue;
      // console.log(this.myValue);
    },
    myValue(newValue) {
      this.$emit("input", newValue);
    },
  },
};
</script>
<style>
.tox-tinymce-aux {
  z-index: 3000 !important;
}
.el-loading-mask {
  z-index: 4000 !important;
}
</style>

第五步:在页面中调用上面封装好的组件

Tip: 1.<el-dialog>中使用TinymceEditor要注意延迟显示,延迟在弹窗显示之后再显示富文本编辑器,因为弹窗元素未加载出来时,编辑器找不到父级元素就无法正常显示

2.赋值和清除富文本编辑器的内容只要针对绑定的值进行清空和赋值操作就行

<template>
<div>
<TinymceEditor
        v-model="diaForm.content"
        :disabled="disabled"
        @onClick="onClick"
        ref="editor"
        v-if="openEditor"
      >
      </TinymceEditor>
</div>
</template>
<script>
import TinymceEditor from "@admin/components/tinymce/index";
export default {
  data() {
    return {
      
    }
  },
  components: {
    TinymceEditor
  }
}

</script>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/12641.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Java day11

第11章 在用户界面上排列组件 11.1 基本的界面布局11.1.1 布置界面11.1.2 顺序布局11.1.3 方框布局11.1.4 网格布局11.1.5 边框布局 11.2 使用多个布局管理器11.3 卡片布局11.3.1 在应用程序中使用卡片布局11.3.2 单元格内边距和面板内边距 11.1 基本的界面布局 11.1.1 布置界…

社科院与杜兰大学中外合作办学金融管理硕士项目——比起过往,前路更值得期待

当结束一天工作陷入沉思时&#xff0c;你有没有特别遗憾的事情呢&#xff0c;人生有太多的不确定性&#xff0c;比起过往&#xff0c;未知的人生更值得我们期待。与其懊恼没完成的遗憾&#xff0c;不如珍惜当下&#xff0c;努力创造未来。人生没有太晚的开始&#xff0c;在职读…

macOS设置环境变量和别名

因为我的mac所用shell是bash&#xff0c;所以本文中涉及的环境变量和别名配置均在~/.zshrc文件中,且在每次配置完成后&#xff0c;需要执行source ~/.zshrc命令使配置文件生效 环境变量 通过配置环境变量&#xff0c;我们可以将某个路径暴露到全局&#xff0c;这样可以在全局…

【C语言学习3——基本的C语言语法知识2】

C语言学习3——基本的C语言语法知识 标识符关键词什么是字面常量&#xff1f;printf函数printf函数更多用法 #include命令 标识符 在前面的代码中&#xff0c;由我们自己命名&#xff0c;用于指代某一个实体的名称&#xff0c;例如:add&#xff0c;result&#xff0c;函数的参…

android studio ImageView和ImageButton和Button

1.ImageView 1.1代码显示 ImageView img findViewById(R.id.img); img.setImageResource(R.drawable.apple); 1.2XML <ImageViewandroid:layout_width"match_parent"android:layout_height"match_parent"android:id"id/img"android:src&qu…

连接云服务器

前言&#xff1a;相信看到这篇文章的小伙伴都或多或少有一些编程基础&#xff0c;懂得一些linux的基本命令了吧&#xff0c;本篇文章将带领大家服务器如何部署一个使用django框架开发的一个网站进行云服务器端的部署。 文章使用到的的工具 Python&#xff1a;一种编程语言&…

实现开机动画和自定义Toolbar的高级写法

需求是自定义一个Toolbar和全屏展示一个第一次激活App的开机动画 1自定义Toolbar的使用 1仍然是先将工程的theme.xml中设置成NoActionBar <resources xmlns:tools"http://schemas.android.com/tools"><!-- Base application theme. --><style name&…

Spring原理学习(五):一篇讲清楚动态代理(jdk和cglib)的使用、原理和源码

目录 一、jdk动态代理的基本使用 二、cglib动态代理的基本使用 2.1 方法一&#xff1a;method.invoke() 方法反射调用 2.2 方法二&#xff08;spring使用的这个方法&#xff09;&#xff1a; methodProxy.invoke() 2.3 方法三&#xff1a;methodProxy.invokeSuper() 三、…

ChatGPT API接口使用+fine tune微调+prompt介绍

目录 1 接口调用1.1 生成key1.2 接口功能1.2.1 图片生成 (image generation)1.2.2 对话(chat)1.2.3 中文纠错 (Chinese Spelling Correct)1.2.4 关键词提取 &#xff08;keyword extract)1.2.5 抽取文本向量 (Embedding)1.2.6 微调 (fine tune) 2 如何写好prompt2.1分类任务2.2…

Baumer工业相机堡盟工业相机如何联合BGAPISDK和OpenCVSharp实现图像的拉普拉斯算法增强(C#)

Baumer工业相机堡盟工业相机如何联合BGAPISDK和OpenCVSharp实现图像的拉普拉斯算法增强&#xff08;C#&#xff09; Baumer工业相机Baumer工业相机使用图像算法增加图像的技术背景Baumer工业相机通过BGAPI SDK联合OpenCV使用图像增强算法1.引用合适的类文件2.BGAPI SDK在图像回…

【C++】从string开始了解STL

文章目录 1.初识STL1.什么是STL2.STL的版本3.STL的六大组件 2.string1.string类模板2.string类的构造函数3.string内部数据访问4.string的遍历5.string类的迭代器6.string的Capacity相关接口7.string的修改相关接口8.其他接口 1.初识STL 1.什么是STL STL(standard template l…

openpnp - 顶部相机 - 辅助光(环形灯)的电路原理图

文章目录 openpnp - 顶部相机 - 辅助光(环形灯)的电路原理图概述END openpnp - 顶部相机 - 辅助光(环形灯)的电路原理图 概述 同学帮我做的简易灯板设计不太合理, 发热量极大. 想看看商用的环形灯电路啥样的, 如果有可能, 自己做块灯板, 塞进商用环形灯外壳中. 拆解了一个环形…

从TOP25榜单,看半导体之变

据SIA报告显示&#xff0c;2022年全球半导体销售额创历史新高达到5740亿美元。尽管2022年下半年&#xff0c;半导体市场出现了周期性的低迷&#xff0c;但其全年的销售额相较2021年增长了3.3%。 近日&#xff0c;市调机构Gartner发布了全球以及中国大陆TOP25名半导体厂商的排名…

【软考数据库】第二章 程序语言基础知识

目录 2.1 程序设计语言的基本概念2.2 程序设计语言的基本成分2.3 编译程序基本原理 前言&#xff1a; 笔记来自《文老师软考数据库》教材精讲&#xff0c;精讲视频在b站&#xff0c;某宝都可以找到&#xff0c;个人感觉通俗易懂。 2.1 程序设计语言的基本概念 程序设计语言是…

《3-链表》

链表 引言&#xff1a; 存储数组需要内存空间连续&#xff0c;当我们需要申请一个很大的数组时&#xff0c;系统不一定存在这么大的连续内存空间。 而链表则更加灵活&#xff0c;不需要内存是连续的&#xff0c;只要剩余内存空间大小够用即可 1.定义 &#xff1a; 「链表 Lin…

文本批量翻译-批量翻译文件名

批量将英文翻译成中文的软件 批量将英文翻译成中文的软件的主要用途场景主要是在需要大量翻译英文文本到中文的场景下使用&#xff0c;例如&#xff1a; 商务文件翻译&#xff1a;许多企业需要将其商务文件&#xff0c;如合同、报告、信函等翻译成中文&#xff0c;以便其中文读…

Vulnhub项目:MrRobot

靶机地址&#xff1a;Mr-Robot: 1 ~ VulnHub 渗透过程&#xff1a; 先看描述&#xff0c;有3跟keys在这个靶机中 首先确定靶机ip&#xff0c;对靶机开放的端口进行探测 访问靶机地址&#xff0c;出现了很酷炫的web界面&#xff0c;这个mr.robot,是一个美剧&#xff0c;还是挺…

e-STUDIO2010AC•2520AC安装步骤

注意!在室内室外温差比较大的情况下,设备需要在室内静置240分钟以上才可以进行安装。

智慧园区综合管理平台开发基本功能有哪些?

随着智慧城市建设与信息化发展&#xff0c;园区管理也需要更加智能便捷化&#xff0c;于是智慧园区管理系统开发应运而生。智慧园区综合管理系统就是利用物联网、大数据等技术工具&#xff0c;顺应产业园区升级发展需求&#xff0c;实现园区环境、设备、安全、基础管理、资源服…

TensorFlow Lite,ML Kit 和 Flutter 移动深度学习:1~5

原文&#xff1a;Mobile Deep Learning with TensorFlow Lite, ML Kit and Flutter 协议&#xff1a;CC BY-NC-SA 4.0 译者&#xff1a;飞龙 本文来自【ApacheCN 深度学习 译文集】&#xff0c;采用译后编辑&#xff08;MTPE&#xff09;流程来尽可能提升效率。 不要担心自己的…