市面上富文本编辑器有很多,相比较而言我比较推荐wangEditorTinyMCE两款,wangEditor适合简单的富文本编辑场景,易于使用;TinyMCE适合有一定技术基础的开发者使用,可以满足更加复杂的编辑需求。建议新手使用wangEditor来进行开发

实现效果

java 富文本编辑器demo 富文本编辑器开发_html

 

依赖安装

个人感觉wangEditor官网依赖安装时不完整的,官网中缺少一个wangeditor,如果你的项目中不安装可以,可以不用安装,弄了很久都不行,下面是我安装的依赖

npm install @wangeditor/editor --save

npm install @wangeditor/editor-for-vue --save

java 富文本编辑器demo 富文本编辑器开发_ide_02

npm install wangeditor --save

java 富文本编辑器demo 富文本编辑器开发_java 富文本编辑器demo_03

 创建编辑器

<div style="border: 1px solid #ccc">
    <Toolbar
      style="border-bottom: 1px solid #ccc"
      :editor="editor"
      :defaultConfig="toolbarConfig"
      :mode="mode"
    />
    <Editor
      style="height: 300px; overflow-y: hidden"
      v-model="html"
      :defaultConfig="editorConfig"
      :mode="mode"
    />
  </div>

 引入wangEditor中自带的工具栏和文本编辑框,wangEditor默认给配置了完整的工具栏,除了上传需要自己另行配置外其它功能直接用即可

import { Editor, Toolbar } from "@wangeditor/editor-for-vue";

 实现文件上传

视频上传和图片上传原理一样,代码基本相同

editorConfig: {
        MENU_CONF: {
          //   配置上传图片
          uploadImage: {
            server: "",//后端给的文件上传接口
            fieldName: "file",
            meta: {},//后端接口要求携带的参数
            // 请求头
            headers: { token: localStorage.getItem("token")},
            timeout: 5 * 1000, // 5s 超时时间
            //选择文件时的类型限制,默认为['image/*'] 如不想限制,则设置为 []
            allowedFileTypes: ["image/*"],
            maxFileSize: 30 * 1024 * 1024, //1g //设置大点 不然图片过大会报错
            base64LimitSize: 1000000 * 1024, // 1g 以下插入 base64
            // 自定义插入图片
            customInsert(res, insertFn) {
              // res 即服务端的返回结果
              // console.log(res, "res");
              // 从 res 中找到 url alt href ,然后插图图片
              insertFn(url, alt , href);
            },
          },
        },
      },

 工具栏配置

wangEditor默认了自带的所有选项,有需求的也可以自行配置选项的显示和位置

toolbarConfig : {
         toolbarKeys: [//自定义菜单选项,显示的选项
           // 菜单 key
           // "headerSelect",
           // // 分割线
           // "|",

           // // 菜单 key
           // "bold",
           // "italic",
           // // 菜单组,包含多个菜单
           // {
           //   key: "group-more-style", // 必填,要以 group 开头
           //   title: "更多样式", // 必填
           //   iconSvg: "<svg>123</svg>", // 可选
          //   menuKeys: ["through", "code", "clearStyle"], // 下级菜单 key ,必填
           // },
           // "underline",
           // "color",
           "bgColor",
         ],
        excludeKeys: [//隐藏掉的选项
          // 'fullScreen',
          // 'bold', 'underline', 'italic', 'through', 'code', 'sub', 'sup', 'clearStyle', 'color', 'bgColor', 'fontSize', 'fontFamily',
          //  'indent', 'delIndent', 'justifyLeft', 'justifyRight', 'justifyCenter', 'justifyJustify', 'lineHeight', 'insertImage', 'deleteImage',
          //  'editImage', 'viewImageLink', 'imageWidth30', 'imageWidth50', 'imageWidth100', 'divider', 'emotion', 'insertLink', 'editLink',
          // 'unLink', 'viewLink', 'codeBlock', 'blockquote', 'headerSelect', 'header1', 'header2', 'header3', 'header4', 'header5', 'todo',
          // 'redo', 'undo', 'fullScreen', 'enter', 'bulletedList', 'numberedList', 'insertTable', 'deleteTable', 'insertTableRow',
          // 'deleteTableRow', 'insertTableCol', 'deleteTableCol', 'tableHeader', 'tableFullWidth', 'insertVideo', 'uploadVideo', 'editVideoSize',
          //  'uploadImage', 'codeSelectLang','group-more-style
          "sub",
          "sup",
        ],
      };

结尾附个人完整代码

项目中用到的地方较多,直接封装了一个组件

子组件:

<template>
  <div style="border: 1px solid #ccc">
    <Toolbar
      style="border-bottom: 1px solid #ccc"
      :editor="editor"
      :defaultConfig="toolbarConfig"
      :mode="mode"
    />
    <Editor
      style="height: 300px; overflow-y: hidden"
      v-model="html"
      :defaultConfig="editorConfig"
      :mode="mode"
      @onChange="onChange"
      @onCreated="onCreated"
    />
  </div>
</template>
<script>
import { Editor, Toolbar } from "@wangeditor/editor-for-vue";
export default {
  components: { Editor, Toolbar },
  props: {
    content: {
      type: String,
      default: "",
    },
  },
  data() {
    return {
      editor: null,
      html: "",
      toolbarConfig: {},
      editorConfig: {
        placeholder: "请输入内容...",
        MENU_CONF: {
          //   配置上传图片
          uploadImage: {
            server:"",
            fieldName: "file",
            meta: {},
            // 请求头
            headers: { token: localStorage.getItem("token") },
            timeout: 5 * 1000, // 5s 超时时间
            //选择文件时的类型限制,默认为['image/*'] 如不想限制,则设置为 []
            allowedFileTypes: ["image/*"],
            maxFileSize: 30 * 1024 * 1024, //1g //设置大点 不然图片过大会报错
             base64LimitSize: 1000000 * 1024, // 1g 以下插入 base64
            // 自定义插入图片
            customInsert(res, insertFn) {
              // res 即服务端的返回结果
              // console.log(res, "res");
              // 从 res 中找到 url alt href ,然后插图图片
              insertFn(url, alt, href);
            },
          },
          //   配置上传视频
          uploadVideo: {
            server:"",
            fieldName: "file",
            meta: {},
            // 请求头
            headers: { token: localStorage.getItem("token")},
            timeout: 5 * 1000, // 5s 超时时间
            //选择文件时的类型限制,默认为['video/*'] 如不想限制,则设置为 []
            allowedFileTypes: ["video/*"],
            // 自定义插入视频
            customInsert(res, insertFn) {
              insertFn(url, alt, href);
            },
          },
        },
      },
      mode: "default", // 'default' or 'simple'
    };
  },
  methods: {
    onChange(editor) {
      this.$emit("changeData", this.html);
    },
    onCreated(editor) {
      this.editor = Object.seal(editor); // 一定要用 Object.seal() ,否则会报错
      this.toolbarConfig = {
         toolbarKeys: [//自定义菜单选项
           // 菜单 key
           // "headerSelect",
           // // 分割线
           // "|",

           // // 菜单 key
           // "bold",
           // "italic",
           // // 菜单组,包含多个菜单
           // {
           //   key: "group-more-style", // 必填,要以 group 开头
           //   title: "更多样式", // 必填
           //   iconSvg: "<svg>123</svg>", // 可选
           //   menuKeys: ["through", "code", "clearStyle"], // 下级菜单 key ,必填
           // },
           // "underline",
           // "color",
           "bgColor",
         ],
        excludeKeys: [
          // 'fullScreen',
          // 'bold', 'underline', 'italic', 'through', 'code', 'sub', 'sup', 'clearStyle', 'color', 'bgColor', 'fontSize', 'fontFamily',
          //  'indent', 'delIndent', 'justifyLeft', 'justifyRight', 'justifyCenter', 'justifyJustify', 'lineHeight', 'insertImage', 'deleteImage',
          //  'editImage', 'viewImageLink', 'imageWidth30', 'imageWidth50', 'imageWidth100', 'divider', 'emotion', 'insertLink', 'editLink',
          // 'unLink', 'viewLink', 'codeBlock', 'blockquote', 'headerSelect', 'header1', 'header2', 'header3', 'header4', 'header5', 'todo',
          // 'redo', 'undo', 'fullScreen', 'enter', 'bulletedList', 'numberedList', 'insertTable', 'deleteTable', 'insertTableRow',
          // 'deleteTableRow', 'insertTableCol', 'deleteTableCol', 'tableHeader', 'tableFullWidth', 'insertVideo', 'uploadVideo', 'editVideoSize',
          //  'uploadImage', 'codeSelectLang','group-more-style
          "sub",
          "sup",
        ],
      };
    },
  },
  created() {
    this.html = this.content;
  },
  mounted() {},
  beforeDestroy() {
    const editor = this.editor;
    if (editor == null) return;
    editor.destroy(); // 组件销毁时,及时销毁编辑器
  },
};
</script>
<style src="@wangeditor/editor/dist/css/style.css"></style>

父组件

<editor-vue
  class="editor"
  ref="editorVue"
  :content="content"
  @changeData="hChangeData"
/>



import editorVue from "./wangEditor/index.vue";

export default {
  props: {},
  watch: {},
  components: {
    editorVue,
  },
  methods:{
    //获取到富文本编辑器的内容
    hChangeData(editDataHtml) {
      console.log(editDataHtml);
      // 获取最新的html数据
      // this.content = editDataHtml;
      // console.log(this.content);
    },
 }
}