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>

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

相关推荐
戏拈秃笔16 分钟前
前端——在本地搭建Vue单页应用
前端·javascript·vue.js
Elena_Lucky_baby17 分钟前
vue项目创建+eslint+Prettier+git提交规范(commitizen+hooks+husk)
前端·javascript·vue.js
呀呀呀雅楠?44 分钟前
vue3(nuxt3)中使用ref获取不到子组件变量
前端·javascript·vue.js·nuxtjs
小怪瘦791 小时前
Vue3使用PDFJS将后端查到的二进制数据转为图片
java·前端·javascript
前端张三2 小时前
vue2中vuedraggable设置部分元素不可拖拽,不可移动
前端·javascript·vue.js
一颗苹果OMG2 小时前
掌握this指向,让你在变量的拷贝中游刃有余
前端·javascript
GoodStudyAndDayDayUp2 小时前
VSCode创建Vue 项目
ide·vue.js·vscode
墨轩尘2 小时前
axios之CancelToken取消请求
前端·javascript
满分观测网友z2 小时前
方案论证项目实现功能
前端·javascript·vue.js·cesium
象野VH3 小时前
编码与加密
javascript·python