vue项目里面几种富文本编辑器的使用

384 阅读2分钟

第一种:quill-editor

使用如下:

  • 首先引入:
import VueQuillEditor from 'vue-quill-editor';
// require styles
import 'quill/dist/quill.core.css'
import 'quill/dist/quill.snow.css'
import 'quill/dist/quill.bubble.css'
Vue.use(VueQuillEditor, /* { default global options } */)
  • 页面使用,你还可以进行配置
<quill-editor v-model="content" ref="myQuillEditor" :options="editorOption"></quill-editor>
//quill编辑器的字体
import * as Quill from 'quill'  //引入编辑器
var fonts = ['SimSun', 'SimHei','Microsoft-YaHei','KaiTi','FangSong','Arial','Times-New-Roman','sans-serif'];  
var Font = Quill.import('formats/font');  
Font.whitelist = fonts; //将字体加入到白名单 
Quill.register(Font, true);

//quill图片可拖拽上传
import { ImageDrop } from 'quill-image-drop-module';
Quill.register('modules/imageDrop', ImageDrop);

//quill图片可拖拽改变大小
import { ImageResize } from 'quill-image-resize-module';


      // 富文本编辑器配置项:
      editorOption: {
        modules: {
          toolbar: [
             ['bold', 'italic', 'underline', 'strike'],        //加粗,斜体,下划线,删除线
             ['blockquote', 'code-block'],         //引用,代码块
             [{ 'header': 1 }, { 'header': 2 }],               // 标题,键值对的形式;1、2表示字体大小
             [{ 'list': 'ordered'}, { 'list': 'bullet' }],          //列表
             [{ 'script': 'sub'}, { 'script': 'super' }],      // 上下标
             [{ 'indent': '-1'}, { 'indent': '+1' }],          // 缩进
             [{ 'direction': 'rtl' }],                         // 文本方向
             [{ 'size': ['small', false, 'large', 'huge'] }],  // 字体大小
             [{ 'header': [1, 2, 3, 4, 5, 6, false] }],         //几级标题
             [{ 'color': [] }, { 'background': [] }],          // 字体颜色,字体背景颜色
             [{ 'font': fonts }],         //字体
             [{ 'align': [] }],        //对齐方式
             ['clean'],        //清除字体样式
             ['image','video']        //上传图片、上传视频
           ],
            imageDrop: true
        },
        // theme:'bubble'
        theme:'snow',

      }
  • 效果展示

第二种:wangeditor

  • 引入,当然还可以引入表情json文件:
import E from "wangeditor";
// 引入表情:
import expression from "../../assets/expression.json";
import expression02 from "../../assets/expression02.json";
  • 页面使用
<div id="wangeditor">
    <div ref="editorElem"></div>
</div>
  mounted() {
    //   this.editor.txt.html('<p>121212</p>');
    this.editor = new E(this.$refs.editorElem);
    // 编辑器的事件,每次改变会获取其html内容
    this.editor.customConfig.onchange = html => {
      this.editorContent = html;
    };
    this.editor.customConfig.menus = [
      // 菜单配置
      "head", // 标题
      "bold", // 粗体
      "fontSize", // 字号
      "fontName", // 字体
      "italic", // 斜体
      "underline", // 下划线
      "strikeThrough", // 删除线
      "foreColor", // 文字颜色
      "backColor", // 背景颜色
      "link", // 插入链接
      "list", // 列表
      "justify", // 对齐方式
      "quote", // 引用
      "emoticon", // 表情
      "image", // 插入图片
      "table", // 表格
      "code", // 插入代码
      "undo", // 撤销
      "redo" // 重复
    ];
    // 配置颜色:
    this.editor.customConfig.colors = [
      "#000000",
      "#eeece0",
      "#1c487f",
      "#4d80bf",
      "#c24f4a",
      "#8baa4a",
      "#7b5ba1",
      "#46acc8",
      "#f9963b",
      "#ffffff",
      "rgba(255, 0, 0, 0.3)"
    ];
    // 配置字体:
    this.editor.customConfig.fontNames = [
      "宋体",
      "微软雅黑",
      "Arial",
      "Tahoma",
      "Verdana",
      "华文行楷"
    ];
    // 表情面板可以有多个 tab ,因此要配置成一个数组。数组每个元素代表一个 tab 的配置
    this.editor.customConfig.emotions = [
      {
        // tab 的标题
        title: "默认",
        // type -> 'emoji' / 'image'
        type: "image",
        // content -> 数组
        content: [
          {
            alt: "[坏笑]",
            src:
              "http://img.t.sinajs.cn/t4/appstyle/expression/ext/normal/50/pcmoren_huaixiao_org.png"
          },
          {
            alt: "[舔屏]",
            src:
              "http://img.t.sinajs.cn/t4/appstyle/expression/ext/normal/40/pcmoren_tian_org.png"
          }
        ]
      },
      {
        title: "引入",
        type: "image",
        content: this.newExpression
      },
      {
          title: "引入2",
          type: "image",
          content: this.newExpression02
      },
      {
        // tab 的标题
        title: "emoji",
        // type -> 'emoji' / 'image'
        type: "emoji",
        // content -> 数组
        content: ["😀", "😃", "😄", "😁", "😆"]
      }
    ];
    this.editor.create(); // 创建富文本实例
  }
  • 效果展示:

第三种:tinymce

  • 引入:
import tinymce from 'tinymce/tinymce'
import Editor from '@tinymce/tinymce-vue'
import 'tinymce/themes/silver'
// 编辑器插件plugins
import 'tinymce/plugins/image'// 插入上传图片插件
import 'tinymce/plugins/media'// 插入视频插件
import 'tinymce/plugins/table'// 插入表格插件
import 'tinymce/plugins/lists'// 列表插件
import 'tinymce/plugins/wordcount'// 字数统计插件
  • 页面使用:
<div class="tinymce-editor">
    <editor v-model="myValue"
      :init="init"
      :disabled="disabled"
      @onClick="onClick">
    </editor>
  </div>
plugins: {
   type: [String, Array],
   default: 'lists image media table wordcount'
},
toolbar: {
   type: [String, Array],
   default: 'undo redo |  formatselect | bold italic forecolor backcolor | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | lists image media table | removeformat'
},
init: {
        language_url: `${this.baseUrl}/tinymce/langs/zh_CN.js`,
        language: 'zh_CN',
        skin_url: `${this.baseUrl}/tinymce/skins/ui/oxide`,
        content_css: `${this.baseUrl}/tinymce/skins/content/default/content.css`,
        // skin_url: `${this.baseUrl}/tinymce/skins/ui/oxide-dark`, // 暗色系
        // content_css: `${this.baseUrl}/tinymce/skins/content/dark/content.css`, // 暗色系
        height: 300,
        plugins: this.plugins,
        toolbar: this.toolbar,
        branding: false,
        menubar: false,
        // 此处为图片上传处理函数,这个直接用了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)
        }
      },
  • 效果

第四种:kindeditor

  • 创建一个kindeditor.vue,代码如下:
<template>
  <div class="kindeditor">
    <textarea :id="id" name="content" v-model="outContent"></textarea>
  </div>
</template>

<script>
import "kindeditor/kindeditor-all.js";
import "kindeditor/lang/zh-CN.js";
import "kindeditor/themes/default/default.css";

export default {
  name: "kindeditor",
  data() {
    return {
      editor: null,
      outContent: this.content
    };
  },
  props: {
    content: {
      type: String,
      default: ""
    },
    id: {
      type: String,
      required: true
    },
    width: {
      type: String
    },
    height: {
      type: String
    },
    minWidth: {
      type: Number,
      default: 650
    },
    minHeight: {
      type: Number,
      default: 100
    },
    items: {
      type: Array,
      default: function() {
        return [
          "source",
          "|",
          "undo",
          "redo",
          "|",
          "preview",
          "print",
          "template",
          "code",
          "cut",
          "copy",
          "paste",
          "plainpaste",
          "wordpaste",
          "|",
          "justifyleft",
          "justifycenter",
          "justifyright",
          "justifyfull",
          "insertorderedlist",
          "insertunorderedlist",
          "indent",
          "outdent",
          "subscript",
          "superscript",
          "clearhtml",
          "quickformat",
          "selectall",
          "|",
          "fullscreen",
          "/",
          "formatblock",
          "fontname",
          "fontsize",
          "|",
          "forecolor",
          "hilitecolor",
          "bold",
          "italic",
          "underline",
          "strikethrough",
          "lineheight",
          "removeformat",
          "|",
          "image",
          "multiimage",
          "flash",
          "media",
          "insertfile",
          "table",
          "hr",
          "emoticons",
          "baidumap",
          "pagebreak",
          "anchor",
          "link",
          "unlink",
          "|",
          "about"
        ];
      }
    },
    noDisableItems: {
      type: Array,
      default: function() {
        return ["source", "fullscreen"];
      }
    },
    filterMode: {
      type: Boolean,
      default: true
    },
    htmlTags: {
      type: Object,
      default: function() {
        return {
          font: ["color", "size", "face", ".background-color"],
          span: ["style"],
          div: ["class", "align", "style"],
          table: [
            "class",
            "border",
            "cellspacing",
            "cellpadding",
            "width",
            "height",
            "align",
            "style"
          ],
          "td,th": [
            "class",
            "align",
            "valign",
            "width",
            "height",
            "colspan",
            "rowspan",
            "bgcolor",
            "style"
          ],
          a: ["class", "href", "target", "name", "style"],
          embed: [
            "src",
            "width",
            "height",
            "type",
            "loop",
            "autostart",
            "quality",
            "style",
            "align",
            "allowscriptaccess",
            "/"
          ],
          img: [
            "src",
            "width",
            "height",
            "border",
            "alt",
            "title",
            "align",
            "style",
            "/"
          ],
          hr: ["class", "/"],
          br: ["/"],
          "p,ol,ul,li,blockquote,h1,h2,h3,h4,h5,h6": ["align", "style"],
          "tbody,tr,strong,b,sub,sup,em,i,u,strike": []
        };
      }
    },
    wellFormatMode: {
      type: Boolean,
      default: true
    },
    resizeType: {
      type: Number,
      default: 2
    },
    themeType: {
      type: String,
      default: "default"
    },
    langType: {
      type: String,
      default: "zh-CN"
    },
    designMode: {
      type: Boolean,
      default: true
    },
    fullscreenMode: {
      type: Boolean,
      default: false
    },
    basePath: {
      type: String
    },
    themesPath: {
      type: String
    },
    pluginsPath: {
      type: String,
      default: ""
    },
    langPath: {
      type: String
    },
    minChangeSize: {
      type: Number,
      default: 5
    },
    loadStyleMode: {
      type: Boolean,
      default: true
    },
    urlType: {
      type: String,
      default: ""
    },
    newlineTag: {
      type: String,
      default: "p"
    },
    pasteType: {
      type: Number,
      default: 2
    },
    dialogAlignType: {
      type: String,
      default: "page"
    },
    shadowMode: {
      type: Boolean,
      default: true
    },
    zIndex: {
      type: Number,
      default: 811213
    },
    useContextmenu: {
      type: Boolean,
      default: true
    },
    syncType: {
      type: String,
      default: "form"
    },
    indentChar: {
      type: String,
      default: "\t"
    },
    cssPath: {
      type: [String, Array]
    },
    cssData: {
      type: String
    },
    bodyClass: {
      type: String,
      default: "ke-content"
    },
    colorTable: {
      type: Array
    },
    afterCreate: {
      type: Function
    },
    afterChange: {
      type: Function
    },
    afterTab: {
      type: Function
    },
    afterFocus: {
      type: Function
    },
    afterBlur: {
      type: Function
    },
    afterUpload: {
      type: Function
    },
    uploadJson: {
      type: String
    },
    fileManagerJson: {
      type: Function
    },
    allowPreviewEmoticons: {
      type: Boolean,
      default: true
    },
    allowImageUpload: {
      type: Boolean,
      default: true
    },
    allowFlashUpload: {
      type: Boolean,
      default: true
    },
    allowMediaUpload: {
      type: Boolean,
      default: true
    },
    allowFileUpload: {
      type: Boolean,
      default: true
    },
    allowFileManager: {
      type: Boolean,
      default: false
    },
    fontSizeTable: {
      type: Array,
      default: function() {
        return ["9px", "10px", "12px", "14px", "16px", "18px", "24px", "32px"];
      }
    },
    imageTabIndex: {
      type: Number,
      default: 0
    },
    formatUploadUrl: {
      type: Boolean,
      default: true
    },
    fullscreenShortcut: {
      type: Boolean,
      default: false
    },
    extraFileUploadParams: {
      type: Array,
      default: function() {
        return [];
      }
    },
    filePostName: {
      type: String,
      default: "imgFile"
    },
    fillDescAfterUploadImage: {
      type: Boolean,
      default: false
    },
    afterSelectFile: {
      type: Function
    },
    pagebreakHtml: {
      type: String,
      default: "<hr style=”page-break-after: always;” class=”ke-pagebreak” />"
    },
    allowImageRemote: {
      type: Boolean,
      default: true
    },
    autoHeightMode: {
      type: Boolean,
      default: false
    },
    fixToolBar: {
      type: Boolean,
      default: false
    },
    tabIndex: {
      type: Number
    }
  },
  watch: {
    content(val) {
      this.editor && val !== this.outContent && this.editor.html(val);
    },
    outContent(val) {
      this.$emit("update:content", val);
      this.$emit("on-content-change", val);
    }
  },
  mounted() {
    var _this = this;
    _this.editor = window.KindEditor.create("#" + this.id, {
      width: _this.width,
      height: _this.height,
      minWidth: _this.minWidth,
      minHeight: _this.minHeight,
      items: _this.items,
      noDisableItems: _this.noDisableItems,
      filterMode: _this.filterMode,
      htmlTags: _this.htmlTags,
      wellFormatMode: _this.wellFormatMode,
      resizeType: _this.resizeType,
      themeType: _this.themeType,
      langType: _this.langType,
      designMode: _this.designMode,
      fullscreenMode: _this.fullscreenMode,
      basePath: _this.basePath,
      themesPath: _this.cssPath,
      pluginsPath: _this.pluginsPath,
      langPath: _this.langPath,
      minChangeSize: _this.minChangeSize,
      loadStyleMode: _this.loadStyleMode,
      urlType: _this.urlType,
      newlineTag: _this.newlineTag,
      pasteType: _this.pasteType,
      dialogAlignType: _this.dialogAlignType,
      shadowMode: _this.shadowMode,
      zIndex: _this.zIndex,
      useContextmenu: _this.useContextmenu,
      syncType: _this.syncType,
      indentChar: _this.indentChar,
      cssPath: _this.cssPath,
      cssData: _this.cssData,
      bodyClass: _this.bodyClass,
      colorTable: _this.colorTable,
      afterCreate: _this.afterCreate,
      afterChange: function() {
        _this.afterChange;
        _this.outContent = this.html();
      },
      afterTab: _this.afterTab,
      afterFocus: _this.afterFocus,
      afterBlur: _this.afterBlur,
      afterUpload: _this.afterUpload,
      uploadJson: _this.uploadJson,
      fileManagerJson: _this.fileManagerJson,
      allowPreviewEmoticons: _this.allowPreviewEmoticons,
      allowImageUpload: _this.allowImageUpload,
      allowFlashUpload: _this.allowFlashUpload,
      allowMediaUpload: _this.allowMediaUpload,
      allowFileUpload: _this.allowFileUpload,
      allowFileManager: _this.allowFileManager,
      fontSizeTable: _this.fontSizeTable,
      imageTabIndex: _this.imageTabIndex,
      formatUploadUrl: _this.formatUploadUrl,
      fullscreenShortcut: _this.fullscreenShortcut,
      extraFileUploadParams: _this.extraFileUploadParams,
      filePostName: _this.filePostName,
      fillDescAfterUploadImage: _this.fillDescAfterUploadImage,
      afterSelectFile: _this.afterSelectFile,
      pagebreakHtml: _this.pagebreakHtml,
      allowImageRemote: _this.allowImageRemote,
      autoHeightMode: _this.autoHeightMode,
      fixToolBar: _this.fixToolBar,
      tabIndex: _this.tabIndex
    });
  }
};
</script>

<style>
</style>
  • 页面使用:
<editor
      id="editor_id"
      height="500px"
      width="700px"
      :content.sync="editorText"
      :afterChange="afterChange()"
      :loadStyleMode="false"
      @on-content-change="onContentChange"
    ></editor>
<script>
import editor from "./kindEditorCom/kindEditor.vue";
export default {
  name: "app",
  components: {
    editor
  },
  data() {
    return {
      editorText: "直接初始化值", // 双向同步的变量
      editorTextCopy: "" // content-change 事件回掉改变的对象
    };
  },
  methods: {
    onContentChange(val) {
      this.editorTextCopy = val;
      console.log(this.editorTextCopy);
    },
    afterChange() {}
  }
};
</script>
  • 效果:

第五种 UEditor

  • 使用vue-ueditor-wrap的步骤: 1.下载UEditor,如果是vue2.x项目,需要放在static文件夹下面,如果你使用的是 vue-cli 3.x,可以把 UEditor 文件夹放入项目的 public 目录下

2.引入VueUeditorWrap组件

  • import VueUeditorWrap from 'vue-ueditor-wrap' // ES6 Module
  • 或者 const VueUeditorWrap = require('vue-ueditor-wrap') //CommonJS

3.注册组件

  • components: { VueUeditorWrap }
  • 或者在 main.js 里将它注册为全局组件 Vue.component('vue-ueditor-wrap', VueUeditorWrap)

4.可以使用了

<vue-ueditor-wrap v-model="msg" :config="myConfig"></vue-ueditor-wrap>
myConfig: {
       // 编辑器不自动被内容撑高
       autoHeightEnabled: false,
       // 初始容器高度
       initialFrameHeight: 240,
       // 初始容器宽度
       initialFrameWidth: "100%",
       // 上传文件接口(这个地址是我为了方便各位体验文件上传功能搭建的临时接口,请勿在生产环境使用!!!)
       serverUrl: "http://35.201.165.105:8000/controller.php",
       // UEditor 资源文件的存放路径,如果你使用的是 vue-cli 生成的项目,通常不需要设置该选项,vue-ueditor-wrap 会自动处理常见的情况,如果需要特殊配置,参考下方的常见问题2
       UEDITOR_HOME_URL: "/UEditor/"
     }
  • 效果: