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

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 },
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值