vue2使用wangEditor5搭建模拟文档的编辑器快速集成

如图

1、下载依赖

2、elm引入(可省略)

main.js 或者 按需引入

3、cv

javascript 复制代码
<template>
  <div style="background: #f1f3f4">
    <div style="width: 100%; height: 42px">
      <!--  工具栏 -->
      <Toolbar
        id="tool-container"
        style="
          width: 100%;
          background: #ffffff;
          border-bottom: 1px solid #e8e8e8;
          position: fixed;
          top: 0;
          z-index: 999;
          border-top: 1px solid #e5e5ea;
        "
        :editor="editor"
        :defaultConfig="toolbarConfig"
        :mode="mode"
      />
    </div>

    <!-- 包裹盒子 -->
    <div style="width: 100%">
      <!-- 最大盒子 -->
      <div style="width: 100%; background: #f1f3f4; border-radius: 0px">
        <div style="height: 10px"></div>
        <!-- 编辑器 -->
        <div
          style="
            overflow-y: hidden;
            width: 768px;
            margin: 0 auto;
            background-color: #fff;
            border: 1px solid #e8e8e8;
            box-shadow: 0 2px 10px rgb(0 0 0 / 12%);
            padding: 48px 72px;
          "
        >
          <!-- 标题栏 -->
          <div
            style="
              height: 54px;
              margin: 0 10px;
              border-bottom: 1px solid #e8e8e8;
            "
          >
            <el-input
              type="text"
              placeholder="请输入文章标题(1~24个字)"
              v-model="chapterTitle"
              maxlength="24"
              show-word-limit
            >
            </el-input>
          </div>
          <!-- 编辑栏 -->
          <Editor
            id="editor-container"
            style="
              min-height: 800px;
              width: 100%;
              text-align: justify;
              border-bottom: 1px solid #e8e8e8;
            "
            v-model="chapterContent"
            :defaultConfig="editorConfig"
            :defaultContent="jsonContent"
            :mode="mode"
            @onCreated="onCreated"
          >
          </Editor>

          <div style="height: 40px; line-height: 40px; text-align: end">
            Lv Jj
          </div>

          <!-- 进度条 -->
          <el-progress
            v-show="showProgress"
            color="#ff570f"
            :text-inside="true"
            :stroke-width="15"
            :percentage="progress"
          ></el-progress>
        </div>
        <div style="height: 50px"></div>
      </div>
    </div>
  </div>
</template>

<script>
import Vue from "vue";
import { Editor, Toolbar } from "@wangeditor/editor-for-vue";
// import { getOss } from "@/api/upload.js";

export default Vue.extend({
  data() {
    let that = this;
    return {
      progress: 0, // 进度条数据
      showProgress: false, //进度条的显示
      url: "",

      chapterTitle: "", // 章节标题
      chapterContent: "", // 章节内容 编辑器初始化内容的位置

      // editor配置开始 -------------------------------------------------
      editor: null,
      toolbarConfig: {
        // 工具栏配置
        toolbarKeys: [
          // 撤销栏
          "undo",
          "redo",
          "|",

          // 正文栏
          "fontSize",
          "bold",
          {
            key: "group-list",
            title: "列表",
            iconSvg:
              '<svg t="1670983367428" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6698" width="200" height="200"><path d="M187.392 70.656q28.672 0 48.64 19.456t19.968 48.128l0 52.224q0 28.672-19.968 48.64t-48.64 19.968l-54.272 0q-27.648 0-47.616-19.968t-19.968-48.64l0-52.224q0-28.672 19.968-48.128t47.616-19.456l54.272 0zM889.856 70.656q27.648 0 47.616 19.456t19.968 48.128l0 52.224q0 28.672-19.968 48.64t-47.616 19.968l-437.248 0q-28.672 0-48.64-19.968t-19.968-48.64l0-52.224q0-28.672 19.968-48.128t48.64-19.456l437.248 0zM187.392 389.12q28.672 0 48.64 19.968t19.968 48.64l0 52.224q0 27.648-19.968 47.616t-48.64 19.968l-54.272 0q-27.648 0-47.616-19.968t-19.968-47.616l0-52.224q0-28.672 19.968-48.64t47.616-19.968l54.272 0zM889.856 389.12q27.648 0 47.616 19.968t19.968 48.64l0 52.224q0 27.648-19.968 47.616t-47.616 19.968l-437.248 0q-28.672 0-48.64-19.968t-19.968-47.616l0-52.224q0-28.672 19.968-48.64t48.64-19.968l437.248 0zM187.392 708.608q28.672 0 48.64 19.968t19.968 47.616l0 52.224q0 28.672-19.968 48.64t-48.64 19.968l-54.272 0q-27.648 0-47.616-19.968t-19.968-48.64l0-52.224q0-27.648 19.968-47.616t47.616-19.968l54.272 0zM889.856 708.608q27.648 0 47.616 19.968t19.968 47.616l0 52.224q0 28.672-19.968 48.64t-47.616 19.968l-437.248 0q-28.672 0-48.64-19.968t-19.968-48.64l0-52.224q0-27.648 19.968-47.616t48.64-19.968l437.248 0z" p-id="6699"></path></svg>',
            menuKeys: ["bulletedList", "numberedList"],
          },

          "divider",
          "blockquote",
          {
            key: "group-justify",
            title: "对齐",
            iconSvg:
              '<svg viewBox="0 0 1024 1024"><path d="M768 793.6v102.4H51.2v-102.4h716.8z m204.8-230.4v102.4H51.2v-102.4h921.6z m-204.8-230.4v102.4H51.2v-102.4h716.8zM972.8 102.4v102.4H51.2V102.4h921.6z"></path></svg>',
            menuKeys: [
              "justifyLeft",
              "justifyCenter",
              "justifyRight",
              "justifyJustify",
            ],
          },
          "todo",
          {
            key: "group-more-style", // 必填,要以 group 开头
            title: "...", // 必填
            iconSvg:
              '<svg viewBox="0 0 1024 1024"><path d="M204.8 505.6m-76.8 0a76.8 76.8 0 1 0 153.6 0 76.8 76.8 0 1 0-153.6 0Z"></path><path d="M505.6 505.6m-76.8 0a76.8 76.8 0 1 0 153.6 0 76.8 76.8 0 1 0-153.6 0Z"></path><path d="M806.4 505.6m-76.8 0a76.8 76.8 0 1 0 153.6 0 76.8 76.8 0 1 0-153.6 0Z"></path></svg>', // 可选
            menuKeys: [
              "italic",
              "through",
              "underline",
              "sup",
              "sub",
              "indent",
              "delIndent",
              // 'codeBlock',
              // 'code',
              "clearStyle",
              "lineHeight",
            ], // 下级菜单 key ,必填
          },
          "|",

          // 颜色栏
          "bgColor",
          "color",
          "|",
          {
            key: "group-image",
            title: "图片",
            iconSvg:
              '<svg viewBox="0 0 1024 1024"><path d="M959.877 128l0.123 0.123v767.775l-0.123 0.122H64.102l-0.122-0.122V128.123l0.122-0.123h895.775zM960 64H64C28.795 64 0 92.795 0 128v768c0 35.205 28.795 64 64 64h896c35.205 0 64-28.795 64-64V128c0-35.205-28.795-64-64-64zM832 288.01c0 53.023-42.988 96.01-96.01 96.01s-96.01-42.987-96.01-96.01S682.967 192 735.99 192 832 234.988 832 288.01zM896 832H128V704l224.01-384 256 320h64l224.01-192z"></path></svg>',
            menuKeys: ["insertImage", "uploadImage"],
            // menuKeys: ['insertImage']
          },
          {
            key: "group-video",
            title: "视频",
            iconSvg:
              '<svg viewBox="0 0 1024 1024"><path d="M981.184 160.096C837.568 139.456 678.848 128 512 128S186.432 139.456 42.816 160.096C15.296 267.808 0 386.848 0 512s15.264 244.16 42.816 351.904C186.464 884.544 345.152 896 512 896s325.568-11.456 469.184-32.096C1008.704 756.192 1024 637.152 1024 512s-15.264-244.16-42.816-351.904zM384 704V320l320 192-320 192z"></path></svg>',
            menuKeys: ["insertVideo", "uploadVideo"],
            // menuKeys: ['insertVideo']
          },
          "insertLink",
          "emotion",
          "insertTable",
          "|",
        ],
        // 135编辑器的位置
        // insertKeys: {
        //   index: 21, // 插入的位置,基于当前的 toolbarKeys
        //   keys: ['codeSelectLang']
        // }
      },
      // 菜单配置
      editorConfig: {
        placeholder: "输入正文",
        hoverbarKeys: {
          text: {
            menuKeys: [
              "fontSize",
              "insertLink",
              "bulletedList",
              "|",
              "bold",
              "through",
              "color",
              "bgColor",
              "clearStyle",
            ],
          },
          image: {
            menuKeys: ["imageWidth100", "deleteImage"],
          },
          video: {
            menuKeys: [],
          },
        },
        MENU_CONF: {
          // 配置字号
          fontSize: {
            fontSizeList: [
              { name: "H1", value: "20px" },
              { name: "H2", value: "19px" },
              { name: "H3", value: "18px" },
              { name: "正文", value: "17px" },
            ],
          },

          lineHeight: {
            lineHeightList: ["1", "1.5", "1.6", "1.75", "2", "3"],
          },

          // 配置上传图片
          uploadImage: {
            //上传图片
            async customUpload(file, insertFn) {
              // file 即选中的文件
              // 自己实现上传,并得到图片 url alt href
              // 最后插入图片
              console.log(file);

              // 判断文件格式是否符合要求规范
              if (!/\.(bmp|tiff|gif|png|jpeg|jpg)$/.test(file.name)) {
                alert("图片类型必须是,bmp/tiff/gif/png/jpeg/jpg中的一种");
                return false;
              }

              that
                .getClient()
                .then(function (client) {
                  client
                    .put("zsdl/image/" + new Date().getTime(), file)
                    .then(function (res) {
                      that.$message.success("上传图片成功");
                      // 上传图片,返回地址
                      console.log(res, "res-----");
                      console.log("上传图片sucess:" + res.url);
                      // 回显图片
                      insertFn(res.url);
                    })
                    .catch(function (err) {
                      // console.log('上传失败')
                      that.$message.error(err);
                      // console.log(err)
                    });
                })
                .catch(function (error) {
                  that.$message.error(error.message);
                  // console.log('失败' + error.message)
                });
            },

            maxFileSize: 10 * 1024 * 1024, // 10M  图片大小限制

            fieldName: "file", //上传类型

            allowedFileTypes: [
              "bmp/*",
              "tiff/*",
              "gif/*",
              "png/*",
              "jpeg/*",
              "jpg",
            ], // 选择文件时的类型限制,默认为 ['image/*'] 。如不想限制,则设置为 []

            // 自定义上传参数,传递图片时需要带一些参数过去写在这。参数会被添加到 formData 中,一起上传到服务端。
            meta: {
              // token: 'xxx',
              // otherKey: 'yyy'
              // file:''
            },

            // 将 meta 拼接到 url 参数中,默认 false
            metaWithUrl: false,

            // 自定义设置请求头,比如添加token之类的
            headers: {
              // Accept: 'text/x-json',
              // otherKey: 'xxx'
            },

            // 跨域是否传递 cookie ,默认为 false
            withCredentials: true,

            // 超时时间,默认为 10 秒
            timeout: 10 * 1000,

            // 上传进度的回调函数,可以用来显示进度条
            onProgress(progress) {
              // progress 是 0-100 的数字
              console.log("progress", progress);
            },

            // 自定义插入图片
            customInsert(res, insertFn) {
              // 因为自定义插入导致onSuccess与onFailed回调函数不起作用,自己手动处理
              // 先关闭等待的Message
              this.Message.closeAll();
              if (res.code === 200) {
                this.Message.success({
                  message: `${res.data.originalName} 上传成功`,
                });
              } else {
                this.Message.error({
                  message: `${res.data.originalName} 上传失败,请重新尝试`,
                });
              }
              insertFn(res.data.link, res.data.name, res.data.link);
            },

            // 单个文件上传成功之后
            onSuccess(file, res) {
              console.log(`${file.name} 上传成功`, res);
            },

            // 单个文件上传失败
            onFailed(file, res) {
              console.log(`${file.name} 上传失败`, res);
            },

            // 上传错误,或者触发 timeout 超时
            onError(file, err, res) {
              console.log(`${file.name} 上传出错`, err, res);
            },
          },

          // 配置上传视频
          uploadVideo: {
            //上传视频
            async customUpload(file, insertFn) {
              // file 即选中的文件
              // 自己实现上传,并得到图片 url alt href
              // 最后插入图片
              console.log(file);

              // 判断文件格式是否符合要求规范
              if (
                !/\.(mpeg|avi|navi|asf|wmv|mov|3gp|mp4|m4v|vob)$/.test(
                  file.name
                )
              ) {
                alert(
                  "视频类型必须是,mpeg/avi/navi/asf/wmv/mov/3gp/mp4/m4v/vob中的一种"
                );
                return false;
              }

              that
                .getClient()
                .then(function (client) {
                  client
                    .multipartUpload(
                      "zsdl/video/" + new Date().getTime(),
                      file,
                      {
                        progress(p) {
                          console.log(p, "进度-----");
                          that.showProgress = true;
                          if (p == 1) {
                            setTimeout(() => {
                              that.$message.success("上传成功");
                              that.showProgress = false;
                            }, 3000);
                          }
                          that.progress = Number((p * 100).toFixed(0));
                          that.progress =
                            that.progress > 100 ? 100 : that.progress;
                        },
                      }
                    )

                    // .put('zsdl/video/' + new Date().getTime(), file)
                    .then(function (res) {
                      that.$message.success("上传视频成功");
                      // 上传视频,返回地址
                      console.log(res, "res-----");
                      // that.videoAddress = res.res.requestUrls[0].split('?')[0] //这个也很重要,必须切割,要不链接显示错误
                      console.log(
                        "上传视频sucess:" +
                          res.res.requestUrls[0].split("?")[0]
                      );
                      // 回显视频
                      insertFn(res.res.requestUrls[0].split("?")[0]);
                    })
                    .catch(function (err) {
                      // console.log('上传失败')
                      that.$message.error(err);
                      // console.log(err)
                    });
                })
                .catch(function (error) {
                  that.$message.error(error.message);
                  // console.log('失败' + error.message)
                });
            },

            // 单个文件的最大体积限制,默认为 10M
            maxFileSize: 50 * 1024 * 1024, // 50M

            fieldName: "your-custom-name", //上传类型

            // 最多可上传几个文件,默认为 5
            maxNumberOfFiles: 3,

            allowedFileTypes: [
              "mpeg/*",
              "avi/*",
              "navi/*",
              "asf/*",
              "wmv/*",
              "mov/*",
              "3gp/*",
              "mp4/*",
              "m4v/*",
              "vob/*",
            ], // 选择文件时的类型限制,默认为 ['video/*'] 。如不想限制,则设置为 []

            // 自定义上传参数,传递图片时需要带一些参数过去写在这。参数会被添加到 formData 中,一起上传到服务端。
            meta: {
              // token: 'xxx',
              // otherKey: 'yyy'
            },

            // 自定义设置请求头,比如添加token之类的
            headers: {
              // Accept: 'text/x-json',
              // otherKey: 'xxx'
            },

            metaWithUrl: false, // 将 meta 拼接到 url 参数中,默认 false
            withCredentials: true, // 跨域是否传递 cookie ,默认为 false

            //上传之前触发
            onBeforeUpload(file) {
              // file 选中的文件,格式如 { key: file }
              this.Message({
                message: "视频正在上传中,请耐心等待",
                duration: 0,
                customClass: "uploadTip",
                iconClass: "el-icon-loading",
                showClose: true,
              });
              return file;
              // 可以 return
              // 1. return file 或者 new 一个 file ,接下来将上传
              // 2. return false ,不上传这个 file
            },

            // 自定义插入视频
            customInsert(res, insertFn) {
              // 因为自定义插入导致onSuccess与onFailed回调函数不起作用,自己手动处理
              // 先关闭等待的Message
              this.Message.closeAll();
              if (res.code === 200) {
                this.Message.success({
                  message: `${res.data.originalName} 上传成功`,
                });
              } else {
                this.Message.error({
                  message: `${res.data.originalName} 上传失败,请重新尝试`,
                });
              }
              insertFn(res.data.link, res.data.link);
            },

            // 上传进度的回调函数,可以用来显示进度条
            onProgress(progress) {
              // progress 是 0-100 的数字
              console.log("progress", progress);
            },

            // // 单个文件上传成功之后
            onSuccess(file, res) {
              console.log(`${file.name} 上传成功`, res);
            },

            // 单个文件上传失败
            onFailed(file, res) {
              console.log(`${file.name} 上传失败`, res);
            },

            // 上传错误,或者触发 timeout 超时
            onError(file, err, res) {
              console.log(`${file.name} 上传出错`, err, res);
            },

            // 插入图片到富文本编辑器回显
            // customInsert(res, insertFn) {
            // console.log(res, '视频插入')
            // res 即服务端的返回结果
            // let url = res.data.url;
            // let poster = res.data.poster;
            // 从 res 中找到 url poster ,然后插入
            //参数url是视频地址,poster是视频封面图片,后端如果不返回,可以考虑写死一个固定的封面图
            // insertFn(url, poster)
            // }
          },
        },
      },
      // 默认编辑栏的配置
      jsonContent: [
        {
          type: "paragraph",
          children: [{ text: "", fontSize: "17px" }],
          // lineHeight ,关于默认行高的设置,可查看源码或通过官方demo
          // https://www.wangeditor.com/demo/index.html
          // 输入文字,设置默认字体、行高之后 在控制台输入 ,this.editor.children 会显示如下内容:
          /*
           *[{"type": "paragraph", "children": [ {  "text": "faskdfjaslkdfj" } ], "lineHeight": "2.5" } ]
           * 按对应格式设置 jsonContent 即可
           * */
          fontSize: "17px",
          lineHeight: 1.75,
          color: "#4a4a4a",
        },
        // {
        //   type: 'image',
        //   imageWidth100: true
        // }
      ],
      mode: "default", // or 'simple'
    };
  },

  mounted() {},

  methods: {
    //获取oss阿里云图上传的client
    // getClient() {
    //   return new Promise((resolve) => {
    //     getOss({})
    //       .then((res) => {
    //         // console.log(res.data)
    //         const OSS = require("ali-oss");
    //         let clinet = new OSS({
    //           accessKeyId: xxx,
    //           accessKeySecret: xxx,
    //           bucket: "xxx",
    //           region: "xxx",
    //           stsToken: xxx,
    //         });
    //         resolve(clinet);
    //       })
    //       .catch((error) => {
    //         resolve(error.message);
    //       });
    //   });
    // },

    // wangeditor的方法---必须要用
    onCreated(editor) {
      this.editor = Object.seal(editor); // 一定要用 Object.seal() ,否则会报错
    },
  },

  computed: {},

  components: { Editor, Toolbar },

  activated() {
    // console.log('actived')
    let docClasses = document.body.classList;
    docClasses.add("white-content");
  },

  deactivated() {
    // console.log('deactivated')
    let docClasses = document.body.classList;
    docClasses.remove("white-content");
  },

  beforeDestroy() {
    const editor = this.editor;
    if (editor == null) return;
    editor.destroy(); // 组件销毁时,及时销毁编辑器
  },
});
</script>

<style src="@wangeditor/editor/dist/css/style.css"></style>

<style>
* {
  margin: 0;
  padding: 0;
}
#tool-container {
  display: flex;
  justify-content: center;
}
.el-input__inner {
  width: 748px;
  border: none;
  font-size: 24px;
  font-weight: 500;
  padding: 0;
  color: #4a4a4a;
}
</style>

上传地址,各自配置。有错误欢迎大佬指教!私必回

相关推荐
supermapsupport30 分钟前
iClient3D for Cesium在Vue中快速实现场景卷帘
前端·vue.js·3d·cesium·supermap
m0_7482548839 分钟前
vue+elementui实现下拉表格多选+搜索+分页+回显+全选2.0
前端·vue.js·elementui
噢,我明白了2 小时前
同源策略:为什么XMLHttpRequest不能跨域请求资源?
javascript·跨域
sanguine__2 小时前
APIs-day2
javascript·css·css3
苹果醋32 小时前
Golang的文件加密工具
运维·vue.js·spring boot·nginx·课程设计
关你西红柿子2 小时前
小程序app封装公用顶部筛选区uv-drop-down
前端·javascript·vue.js·小程序·uv
济南小草根3 小时前
把一个Vue项目的页面打包后再另一个项目中使用
前端·javascript·vue.js
小木_.3 小时前
【python 逆向分析某有道翻译】分析有道翻译公开的密文内容,webpack类型,全程扣代码,最后实现接口调用翻译,仅供学习参考
javascript·python·学习·webpack·分享·逆向分析
Aphasia3113 小时前
一次搞懂 JS 对象转换,从此告别类型错误!
javascript·面试
m0_748256564 小时前
Vue - axios的使用
前端·javascript·vue.js