在Vue项目中使用tinymce富文本编辑器

news2024/10/4 13:22:35

TinyMC编辑器简介

TinyMCE是一款易用、且功能强大的所见即所得的富文本编辑器。跟其他富文本编辑器相比,有着丰富的插件,支持多种语言,能够满足日常的业务需求并且免费。

TinyMCE的优势:

开源可商用,基于LGPL2.1

插件丰富,自带插件基本涵盖日常所需功能

接口丰富,可扩展性强,有能力可以无限拓展功能

界面好看,符合现代审美

提供经典、内联、沉浸无干扰三种模式(详见“介绍与入门”)

对标准支持优秀(自v5开始)

多语言支持,官网可下载几十种语言。

下图为我开启全部功能的截图

TinyMCE中文文档地址:TinyMCE中文文档中文手册

1、安装

vue-cli版本:3.x+

安装tinymce

npm install tinymce@6.3 -S 

安装tinymce-vue

npm install --save tinymce "@tinymce/tinymce-vue@^5"

这两个组件安装完之后,在public目录下新建文件夹tinymce,目录建好后,找到node_modules文件夹下的tinymce/skins目录,将skins目录复制到我们创建的tinymce文件夹内。

vue-cli版本:2.x

安装tinymce,我安装的是5.10.7

npm install tinymce@5.10.7 -S 

安装tinymce-vue

npm install --save tinymce "@tinymce/tinymce-vue@^3"

安装之后,在 node_modules 中找到 tinymce/skins 目录,然后将 skins 目录拷贝到 public/tinymce 目录下

注意: 如果是使用 vue-cli 3.x 之前构建的 typescript 项目,就放到 static 目录下,和文中所有 public 目录一样处理

tinymce 默认是英文界面,所以还需要下载一个中文语言包

然后将这个语言包放到相同 public/tinymce 目录下新建的langs文件目录中

这个是vue-cli3项目的放法

2、配置中文语言

到官网下载中文语言包 zh_CN.js

在刚才创建的static/tinymce文件夹内再新建langs文件夹,用来存放我们下载的中文语言包,如下图所示

 vue-cli2.x 同理

​​3.组件

<template>
  <Editor id="tinymce" v-model="content" :init="init"></Editor>
</template>

<script>
import tinymce from "tinymce";
import Editor from "@tinymce/tinymce-vue";
import "tinymce/themes/silver/theme";
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/icons/default/icons";
import "tinymce/themes/silver";
import "tinymce/plugins/media";
import "tinymce/plugins/contextmenu";
import "tinymce/plugins/colorpicker";
import "tinymce/plugins/textcolor";
import "tinymce/plugins/preview";
import "tinymce/plugins/advlist";
import "tinymce/plugins/codesample";
import "tinymce/plugins/hr";
import "tinymce/plugins/fullscreen";
import "tinymce/plugins/textpattern";
import "tinymce/plugins/searchreplace";
import "tinymce/plugins/autolink";
import "tinymce/plugins/directionality";
import "tinymce/plugins/visualblocks";
import "tinymce/plugins/visualchars";
import "tinymce/plugins/template";
import "tinymce/plugins/charmap";
import "tinymce/plugins/nonbreaking";
import "tinymce/plugins/insertdatetime";
import "tinymce/plugins/imagetools";
import "tinymce/plugins/autosave";
import "tinymce/plugins/autoresize";
import "tinymce/plugins/paste";
import "tinymce/plugins/print";
import "tinymce/plugins/quickbars";
import "tinymce/plugins/emoticons";
import "tinymce/plugins/bbcode";
import "tinymce/plugins/tabfocus";
// 扩展插件
// import "/tinymce/plugins/lineheight/plugin";
// import "/tinymce/plugins/bdmap/plugin";

import { uploadImageFile, deleteFile } from "@/api/geekplus/articles";
export default {
  name: "TinyEditor",
  components: { Editor },
  props:{
    value: {
      type: String,
      default: "",
    },
  },
  data() {
    return {
      content: "",
      //fileList: [],
      allImageList: [],
      baseHost: window.location.host,
      baseApi: process.env.VUE_APP_BASE_API,
      init: {
        language_url: "/tinymce/langs/zh_CN.js", // 语言包位置,因为放在public下所以可以省略public
        selector: "#tinymce", //tinymce的id
        // auto_focus: 'element1',
        language: "zh_CN", //语言类型
        skin_url: "/tinymce/skins/ui/oxide",
        height: 650, //编辑器高度
        min_height: 400,
        highlight_on_focus: true,
        // contextmenu_never_use_native: true,//5.0.1
        draggable_modal: true,
        //inline: true,
        // content_style: "p {margin: 2px 0;}",
        init_instance_callback: (editor) => {
            // 更改元素为Div
            editor.execCommand('mceInsertContent', false, '<p></p>')
        },
        browser_spellcheck: true, // 拼写检查
        // elementpath: false, //禁用编辑器底部的状态栏
        // statusbar: false, // 隐藏编辑器底部的状态栏
        // paste_data_images: true, // 允许粘贴图像
        // menubar: false, //最顶部文字信息
        mobile: {
          menubar: true,
          plugins: ["autosave", "lists", "autolink"],
          toolbar: ["undo", "bold", "italic", "styleselect"],
        },
        // mode: "textareas",
        placeholder: "在此处书写...",
        // forced_root_block: '', // 删除在tinymce中自动添加的p标签
        // force_br_newlines : true,
        // force_p_newlines : false,
        preview_styles: "font-size color",
        invalid_styles: {
            '*': 'color font-size', //全局无效样式
            'a': 'background', // 链接禁用背景样式
        },
        plugins:
          "image link code codesample table lists wordcount autosave autolink insertdatetime preview media fullscreen quickbars print template", //就可以增加上面引入的插件,加入下面这一行就可以在toolbar栏显示相应插件。
        branding: false, //是否禁用“Powered by TinyMCE”
        toolbar: [
          {
            name: "history",
            items: ["undo", "redo"],
          },
          {
            name: "styles",
            items: ["styleselect"],
          },
          {
            name:'code',items:['codesample']
          },
          {
            name: "formatting",
            items: ["bold", "italic", "underline", "strikethrough"],
          },
          {
            name: "fonts",
            items: ["fontselect", "fontsizeselect", ],
          },
          {
            name: "colors",
            items: ["forecolor", "backcolor"],
          },
          {
            name: "media&link",
            items: ["link", "image", "media"],
          },
          {
            name: "alignment",
            items: ["alignleft", "aligncenter", "alignright", "alignjustify"],
          },
          {
            name: "indentation",
            items: ["outdent", "indent"],
          },
          {
            name: "blockquote",
            items: ["blockquote"],
          },
          {
            name: "table",
            items: ["table"],
          },
          {
            name: "lists",
            items: ["numlist", "bullist"],
          },
          {
            name: "tools",
            items: ["preview", 'print', "fullscreen"],
          },
        ],
        //toolbar: "undo redo | fontselect fontsizeselect link autolink lineheight | forecolor backcolor | bold italic underline strikethrough | alignleft aligncenter alignright alignjustify | image imagetools | code | h1 h2 h3 h4 h5 blockquote table numlist bullist outdent indent preview fullscreen", //工具栏
        // toolbar_groups: {
        //     formatting: {
        //     icon: 'bold',
        //     tooltip: 'Formatting',
        //     items: 'bold italic underline | superscript subscript'
        //     }
        // },
        toolbar_mode: "sliding",
        //toolbar_sticky: true,
        image_caption: true,
        images_upload_handler: (blobInfo, success, failure, progress) => {
          this.uploadFile(blobInfo, success, failure);
        },
        //file_picker_callback: "",
        fontsize_formats:
          "8px 10px 12px 14px 16px 18px 24px 36px 48px 56px 72px",
        font_formats:
          "微软雅黑=Microsoft YaHei,Helvetica Neue,PingFang SC,sans-serif;苹果苹方=PingFang SC,Microsoft YaHei,sans-serif;宋体=simsun,serif;仿宋体=FangSong,serif;黑体=SimHei,sans-serif;Arial=arial,helvetica,sans-serif;Arial Black=arial black,avant garde;Book Antiqua=book antiqua,palatino;",
        // lineheight_formats: '1 1.1 1.2 1.3 1.4 1.5 2',
        // link_list: [
        // { title: '预置链接1', value: 'http://www.tinymce.com' },
        // { title: '预置链接2', value: 'http://tinymce.ax-z.cn' }
        // ],
        // image_list: [
        // { title: '预置图片1', value: 'https://www.tiny.cloud/images/glyph-tinymce@2x.png' },
        // { title: '预置图片2', value: 'https://www.baidu.com/img/bd_logo1.png' }
        // ],
        // image_class_list: [
        // { title: 'None', value: '' }
        // // { title: 'Some class', value: 'class-name' }
        // ],
        tabfocus_elements: "tinymce",
        importcss_append: true,
        textpattern_patterns: [
          { start: "*", end: "*", format: "italic" },
          { start: "**", end: "**", format: "bold" },
          { start: "#", format: "h1" },
          { start: "##", format: "h2" },
          { start: "###", format: "h3" },
          { start: "####", format: "h4" },
          { start: "#####", format: "h5" },
          { start: "######", format: "h6" },
          { start: "1. ", cmd: "InsertOrderedList" },
          { start: "* ", cmd: "InsertUnorderedList" },
          { start: "- ", cmd: "InsertUnorderedList" },
        ],
        setup: (editor) => {
            // 自定义toolbar按钮,需要在toolbar添加
            editor.ui.registry.addButton('testBtn', {
            text: `按钮文字`,
            tooltip: '按钮提示',
            onAction: () => editor.insertContent('<a href="https://www.geekplus.xyz" target="_blank">test text</a>')
            })
        },
      },
    };
  },
  //   init: {
  //     setup: (Editor) => {
  //       // 初次化编辑器
  //       Editor.on("init", () => {
  //         Editor.setContent(this.value);
  //       });
  //     },
  //   },
  watch: {
    value(newVal) {
      //this.content = newValue;
      //用户vue绑定回显
      //if (this.isInit) {
      //this.isInit = false;
      //this.getContent();
    //   this.$nextTick(() => {
    //     const editor = tinymce.get("tinymce");
    //     editor.activeEditor.getContent()
    //     editor.setContent(newVal);
    //   });
      //}
      this.content=newVal;
    },
    content(newValue) {
      this.$emit("input", newValue);
      console.log(newValue);
    }
  },
  //获取焦点光标到最后面keepLastIndex (obj, window) {if (window.getSelection) { //ie11 10 9 ff safariobj.focus(); //解决ff不获取焦点无法定位问题var range = window.getSelection(); //创建rangerange.selectAllChildren(obj); //range 选择obj下所有子内容range.collapseToEnd(); //光标移至最后} else if (document.selection) { //ie10 9 8 7 6 5var range = document.selection.createRange(); //创建选择对象range.moveToElementText(obj); //range定位到objrange.collapse(false); //光标移至最后range.select();}}
  mounted() {
    tinymce.init({});
    this.$nextTick(() => {
      var ifra = document.getElementById("tinymce_ifr");
    //   this.keepLastIndex(
    //     ifra.contentWindow.document.getElementById("tinymce")
    //   );
    });
  },
  methods: {
    // file_picker_callback: function(callback, value, meta) {
    //     // Provide file and text for the link dialog
    //     if (meta.filetype == 'file') {
    //         callback('mypage.html', {text: 'My text'});
    //     }
    //     // Provide image and alt text for the image dialog
    //     if (meta.filetype == 'image') {
    //         callback('myimage.jpg', {alt: 'My alt text'});
    //     }
    //     // Provide alternative source and posted for the media dialog
    //     if (meta.filetype == 'media') {
    //         callback('movie.mp4', {source2: 'alt.ogg', poster: 'image.jpg'});
    //     }
    // },
    getContent(){
        var cnt = tinymce.editors['tinymce'].getContent();
        //console.log(cnt);
    },
    //自定义上传函数
    uploadFile(blobInfo, success, failure, progress) {
      let formData = new FormData();
      formData.append("file", blobInfo.blob());
      uploadImageFile(formData)
        .then((response) => {
          //console.log(response);
          var serverUrl = response.url;
          let uploadSuccess = {};
          const imageUrl =
            "https://www.geekplus.xyz" + this.baseApi + serverUrl;
          // this.$message({
          //   message: "上传" + response.msg,
          //   type: "success",
          // });
          //success函数获取我们反悔的图片url,就实现了插入编辑器了
          success(imageUrl);
          // this.content += url
          uploadSuccess = { filePath: serverUrl };
          this.allImageList.push(uploadSuccess);
        })
        .catch((error) => {
          //console.log(error);
          failure("Invalid JSON: " + error.msg);
          this.$message({
            message: error.msg,
            type: "error",
            showClose: true,
          });
        });
    },
  },
  destroyed() {},
};
</script>
<style>
</style>

4.组件使用

<tiny-editor v-model="form.articleContent" @onSelectionChange="onEditorBlur($event)">
</tiny-editor>
import TinyEditor from "@/components/TinyMCE"
components: { TinyEditor },

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

虚拟机安装 Ubuntu 桌面版

目录 1、下载系统镜像 2、新建虚拟机 3、配置虚拟机 1、下载系统镜像 Ubuntu桌面版最新版本下载地址&#xff1a;Download | Ubuntu 桌面版 Ubuntu桌面版历史版本下载地址&#xff1a;Download | Ubuntu 桌面版&#xff08;历史版本&#xff09; 以下载18.04 版本为例&am…

【三位重建】NeRF原理+代码讲解

文章目录一、技术原理1.概览2.基于神经辐射场&#xff08;Neural Radiance Field&#xff09;的体素渲染算法3.体素渲染算法4.位置信息编码&#xff08;Positional encoding&#xff09;5.多层级体素采样二、代码讲解1.数据读入2.创建nerf1.计算焦距focal与其他设置2.get_embed…

CSS学习|这一篇就够了|笔记|总结|(超详细讲解)

&#x1f648;作者简介&#xff1a;练习时长两年半的Java up主 &#x1f649;个人主页&#xff1a;老茶icon &#x1f64a; ps:点赞&#x1f44d;是免费的&#xff0c;却可以让写博客的作者开兴好久好久&#x1f60e; &#x1f4da;系列专栏&#xff1a;Java全栈&#xff0c;计…

误删除文件怎么找回 数据恢复用这些方法

误删除文件是很多人都会遇到的问题&#xff0c;尤其是在Windows 10系统中&#xff0c;有时候我们不小心按了ShiftDelete或者清空了回收站&#xff0c;就会导致文件永久消失。那么&#xff0c;误删除文件怎么找回呢?本文将介绍四种数据恢复的方法&#xff0c;帮助你轻松将误删除…

【PCIE体系结构五】PCIE配置和地址空间

&#x1f449;个人主页&#xff1a;highman110 &#x1f449;作者简介&#xff1a;一名硬件工程师&#xff0c;持续学习&#xff0c;不断记录&#xff0c;保持思考&#xff0c;输出干货内容 参考书籍&#xff1a; PCI_Express体系结构导读、 深入浅出SSD&#xff1a;固态存储…

【Java版oj】day30最难的问题、因子个数

目录 一、最难的问题 &#xff08;1&#xff09;原题再现 &#xff08;2&#xff09;问题分析 &#xff08;3&#xff09;完整代码 二、因子个数 &#xff08;1&#xff09;原题再现 &#xff08;2&#xff09;问题分析 &#xff08;3&#xff09;完整代码 三、DFS深度优…

Python实现批量图片下载及去重处理

背景 在爬虫应用开发中&#xff0c;常常需要批量下载图片&#xff0c;并对图片进行去重处理。Python 是一种非常流行的编程语言&#xff0c;也是开发爬虫应用的首选&#xff0c;本文将介绍如何使用 Python 下载图片&#xff0c;并对下载的图片进行去重处理。 内容 首先&…

win10彻底永久关闭自动更新【亲测有效】

一、禁用Windows Update服务 1、同时按下键盘 Win R&#xff0c;打开运行对话框&#xff0c;然后输入命令 services.msc &#xff0c;点击下方的“确定”打开服务&#xff0c;如下图所示。 2、找到 Windows Update 这一项&#xff0c;并双击打开&#xff0c;如图所示。 3、右击…

【行为型模式】责任链模式

文章目录1、简介2、结构3、实现方式3.1、案例引入3.2、结构分析3.3、具体实现4、责任链优缺点5、应用场景1、简介 责任链模式(Chain of Responsibility)是一种行为型设计模式&#xff0c;它允许对象在链上依次处理请求&#xff0c;用户只需要将请求发送到责任链上即可&#xf…

CocosCreator实战篇 | 实现刮刮卡和橡皮擦 | 擦除效果

&#x1f4e2;博客主页&#xff1a;https://blog.csdn.net/dxt19980308 &#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01; &#x1f4e2;本文由肩匣与橘编写&#xff0c;首发于CSDN&#x1f649; &#x1f4e2;生活依旧是美好而…

【SSM框架】spring的创建与使用

spring的创建与使用Spring项目的创建创建一个maven项目添加Spring依赖添加启动类将bean存储到Spring 中创建bean对象将bean对象存储到Spring容器中从Spring中获取bean创建Spring(上下文)对象从Spring中获取到bean对象使用Bean&#xff08;非必须&#xff09;从spring中获取Bean…

奇瑞版Model 3与Model Y登场:正式进军高端纯电

作者 | Amy 编辑 | 德新4月7日&#xff0c;奇瑞在北京举办「新能源之夜」。整场发布会都在传递一个讯息&#xff1a;奇瑞搞新能源&#xff0c;要大搞特搞&#xff01; 奇瑞在这场发布会上&#xff0c;对新能源的战略、技术、品牌和产品作了全面梳理。其中最引人注目的是&#x…

环信web、uniapp、微信小程序sdk报错详解---注册篇(二、三)

项目场景&#xff1a; 记录对接环信sdk时遇到的一系列问题&#xff0c;总结一下避免大家再次踩坑。这里主要针对于web、uniapp、微信小程序在对接环信sdk时遇到的问题。 注册篇(二) 注册用户报错400 原因分析&#xff1a; 从console控制台输出及network请求返回入手分析 可以看…

【三十天精通Vue 3】第十一天 Vue 3 过渡和动画详解

✅创作者&#xff1a;陈书予 &#x1f389;个人主页&#xff1a;陈书予的个人主页 &#x1f341;陈书予的个人社区&#xff0c;欢迎你的加入: 陈书予的社区 &#x1f31f;专栏地址: 三十天精通 Vue 3 文章目录引言一、Vue 3 过度和动画概述1.1过度和动画的简介二、Vue 3 过度2…

Java 集合框架面试问题集锦

Java集合框架&#xff08;例如基本的数据结构&#xff09;里包含了最常见的Java常见面试问题。很好地理解集合框架&#xff0c;可以帮助你理解和利用Java的一些高级特性。下面是面试Java核心技术的一些很实用的问题。 Q&#xff1a;最常见的数据结构有哪些&#xff0c;在哪些场…

telnet远程管理linux主机及Zlib、openssl、openssh升级

目录 一、telnet远程管理主机 1、检查是否安装telnet 2、安装telnet服务 3、测试telnet登录 二、zlib、openssl、openssh升级 1、下载zlib包 2、下载openssl包 3、下载openssh包 4、 编译安装zlib 5、编译安装openssl 6、准备升级openssh环境 ①注意必须使用telne…

LLM 快人一步的秘籍 —— Zilliz Cloud,热门功能详解来啦!

最近&#xff0c;我们发布了可处理十亿级向量数据的 Zilliz Cloud GA 版本&#xff0c;为用户提供开箱即用的向量数据库服务&#xff0c;大大降低了数据库的运维成本。 看过上一篇文章《可处理十亿级向量数据&#xff01;Zilliz Cloud GA 版本正式发布》的朋友们知道&#xff0…

【SSM】Spring6(十.面向切面编程AOP)

文章目录1.AOP2. AOP的七大术语3. 切点表达式4.使用Spring的AOP4.1 环境准备4.2 基于AspectJ的AOP注解式开发步骤4.3 所有通知类型4.4 切面顺序4.5 通用切点4.6 获取目标方法的方法签名4.7 全注解式开发4.8 基于XML配置的AOP5. 案例&#xff1a;事务处理1.AOP 将与核心业务无关…

Visual Studio Code跳转到CSS定义

Visual Studio Code 快速跳转到 VUE文件 或 CSS文件的定义位置&#xff08;跳转到class定义&#xff0c;跳转到css定义&#xff09;&#xff0c;插件Css Peek、Vue Peek 对提升开发效率上&#xff0c;事半功倍。 目录 1、跳转到CSS定义 1.1、CSS Peek 1.2、Vue Peek 2、其他…

舌体胖瘦的自动分析-曲线拟合-或许是最简单判断舌形的方案(六)

返回至系列文章导航博客 1 简介 在中医智能舌诊项目中需要舌体胖瘦的自动分析 舌体胖瘦是中医诊断中重要的观察依据&#xff0c;。胖大舌“舌色淡白&#xff0c;舌体胖嫩&#xff0c;比正常舌大而厚&#xff0c;甚至充满口腔”&#xff0c;主脾肾阳虚&#xff0c;气化失常&am…