美文网首页
vue2使用富文本编辑器

vue2使用富文本编辑器

作者: 蜗牛的学习方法 | 来源:发表于2024-06-27 09:38 被阅读0次

    目前接触到的编辑器有三种
    1、tinymce-editor
    2、@wangeditor/editor-for-vue
    3、vue-quill-editor

    现在主要介绍一下这三种编辑器的用法

    tinymce-editor

    @wangeditor/editor-for-vue

    编辑器样式,这个样式还是比较好看的,功能也比较好用


    image.png

    1、首先下载插件

    yarn add  @wangeditor/editor  // 下载版本是^5.1.23
    yarn add  @wangeditor/editor-for-vue   //下载版本是 1.0.2
    yarn add  @wangeditor/plugin-upload-attachment // 上传附件插件 ^1.1.0
    

    2、封装使用

    //封装富文本编辑器
    <template>
      <div :class="{ 'border-line': border }">
        <Toolbar style="border-bottom: 1px solid #ccc" :editor="editor" :defaultConfig="toolbarConfig" :mode="mode" />
        <Editor
          :style="{ height }"
          v-model="html"
          :defaultConfig="editorConfig"
          :mode="mode"
          @onCreated="onCreated"
          @onChange="onChange"
        />
      </div>
    </template>
    <script>
    import Vue from "vue";
    import { Boot } from "@wangeditor/editor";
    import attachmentModule from "@wangeditor/plugin-upload-attachment";
    import { Editor, Toolbar } from "@wangeditor/editor-for-vue";
    import "@wangeditor/editor/dist/css/style.css";
    import axios from "axios ";
    
    Boot.registerModule(attachmentModule);
    
    export default {
      components: { Editor, Toolbar },
      props: {
        //border
        border: {
          type: Boolean,
          default: false,
        },
        /* 编辑器的内容 */
        value: {
          type: String,
          default: "",
        },
        // 高度
        height: {
          type: String,
          default: () => "500px",
        },
      },
      data() {
        return {
          editor: null,
          html: "",
          toolbarConfig: {
            excludeKeys: ["fullScreen"],
            insertKeys: {
              index: 24,
              keys: ["uploadAttachment"],
            },
          },
          editorConfig: {
            placeholder: "请输入内容...",
            scroll: false,
            MENU_CONF: {
              uploadImage: {
                // 自定义上传图片 方法
                customUpload: this.uploadImg,
                // 上传接口设置文件名
                fieldName: "file",
                meta: {
                  token: localStorage.getItem("token"),
                },
              },
              uploadVideo: {
                customUpload: this.uploadVideo,
                fieldName: "file",
                meta: {
                  token: localStorage.getItem("token"),
                },
              },
              uploadAttachment: {
                customUpload: this.uploadFile,
                fieldName: "file",
                meta: {
                  token: localStorage.getItem("token"),
                },
              },
            },
            hoverbarKeys: {
              attachment: {
                menuKeys: ["downloadAttachment"],
              },
            },
          },
    
          mode: "default", //default or 'simple'
        };
      },
      watch: {
        value: {
          handler(val) {
            this.html = val;
          },
          immediate: true,
        },
      },
      mounted() {
        // 模拟 ajax 请求,异步渲染编辑器
      },
      beforeDestroy() {
        const editor = this.editor;
        if (editor == null) return;
        editor.destroy(); // 组件销毁时,及时销毁编辑器
      },
      methods: {
        onChange(editor) {
          this.$emit("input", this.html);
        },
        onCreated(editor) {
          this.editor = Object.seal(editor); // 一定要用 Object.seal() ,否则会报错
        },
        uploadImg(file, insertFn) {
          let imgData = new FormData();
          imgData.append("file", file);
          commonAxios({
            url: `/fileUpload`,
            data: imgData,
            method: "post",
            headers: {
              Authorization:  localStorage.getItem("token"),
            },
          }).then((res) => {
            if (res.success) {
              insertFn(`图片url`);
            } else {
              this.$message.warning(res.errorMessage);
            }
          });
        },
        uploadVideo(file, insertFn) {
          let imgData = new FormData();
          imgData.append("file", file);
          commonAxios({
            url: `/fileUpload`,
            data: imgData,
            method: "post",
            headers: {
              Authorization: localStorage.getItem("token"),
            },
          }).then((res) => {
            if (res.success) {
              insertFn(`视频url`);
            } else {
              this.$message.warning(res.errorMessage);
            }
          });
        },
        uploadFile(file, insertFn) {
          let imgData = new FormData();
          imgData.append("file", file);
          commonAxios({
            url: `/fileUpload`,
            data: imgData,
            method: "post",
            headers: {
              Authorization:  localStorage.getItem("token"),
            },
          }).then((res) => {
            if (res.success) {
              insertFn(
                `附件:${res.resultData.elementName}`,`下载url`);
            } else {
              this.$message.warning(res.errorMessage);
            }
          });
        },
      },
    };
    </script>
    <style lang="less" scoped>
    .border-line {
      border: 1px solid #d6d6d6;
    }
    /deep/.w-e-scroll > div:first-child {
      height: 100%;
      overflow-y: auto;
    }
    </style>
    
    
    <template>
    <editor v-model="content" height="300px" :border="true" />
    </template>
    <script>
    import editor from "./components/editor.vue";
    export default{
      components: {
        editor,
      },
      data(){
        content:''
      }
    }
    </script>
    
    

    这样一个双向绑定的富文本编辑器就可以使用了!

    vue-quill-editor

    这个富文本内容没有上一个多,其中图片和视频也是要自己写上传逻辑


    image.png

    1、下载插件

    yarn add vue-quill-editor
    yarn add quill-image-resize-module //调整大小组件
    yarn add quill-image-drop-module //拖动加载图片组件
    
    

    2、封装

    <template>
      <w-spin :spinning="loading" tip="上传中...">
        <quill-editor
          ref="myQuillEditor"
          v-model="editorContent"
          :options="editorOption"
          @change="onEditorChange($event)"
          @click.native="handleEditAblequestion"
        />
      </w-spin>
    </template>
    <script>
    import "quill/dist/quill.core.css";
    import "quill/dist/quill.snow.css";
    import "quill/dist/quill.bubble.css";
    import { quillEditor, Quill } from "vue-quill-editor";
    // 富文本图片大小
    import imageResize from "quill-image-resize-module"; // 调整大小组件。
    import { ImageDrop } from "quill-image-drop-module"; // 拖动加载图片组件。
    Quill.register("modules/imageResize", imageResize);
    Quill.register("modules/imageDrop", ImageDrop);
    
    export default {
      props: {
        value: {
          type: String,
          default: "",
        },
      },
      components: {
        quillEditor,
      },
      data() {
        return {
          loading: false,
          editorContent: "",
          editorOption: {
            modules: {
              toolbar: {
                container: [
                  ["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: [] }], //字体
                  [{ align: [] }], //对齐方式
                  // ["clean"], //清除字体样式
                  ["image", "video"], //上传图片、上传视频
                ],
                handlers: {
                  video: () => {
                    this.openFileDialog("video");
                  },
                },
              },
              imageResize: {
                displayStyles: {
                  backgroundColor: "black",
                  border: "none",
                  color: "white",
                },
                modules: ["Resize", "DisplaySize", "Toolbar"],
              },
            },
            placeholder: "输入内容...",
          },
        };
      },
      watch: {
        value: {
          handler(newValue) {
            this.editorContent = newValue === null ? "" : newValue;
          },
          deep: true,
          immediate: true,
        },
        editorContent(newValue) {
          this.$emit("input", newValue);
        },
      },
      mounted() {
        this.resetFocus();
      },
      methods: {
        resetFocus() {
          this.$refs.myQuillEditor?.quill?.enable(false);
          // this.$nextTick(() => {
          //   document.querySelector(".content-b").scrollTop = 0;
          // });
        },
        onEditorChange() {
          // console.log(e);
        },
        handleEditAblequestion() {
          this.$refs.myQuillEditor.quill.enable(true);
          this.$refs.myQuillEditor.quill.focus();
        },
        openFileDialog(type) {
          var input = document.createElement("input");
          input.setAttribute("type", "file");
          input.setAttribute("accept", type === "image" ? "image/*" : "video/*");
          input.click();
          let that = this;
          input.onchange = async function () {
            var file = input.files[0];
            const formData = new FormData();
            formData.append("file", file);
            try {
              that.loading = true;
              let res = await that.$axios.post(`上传接口`, formData, {
                headers: {
                  "content-type": "multipart/form-data",
                },
              });
              let url = `返回的url`;
              that.$refs.myQuillEditor.quill.insertEmbed(that.$refs.myQuillEditor.quill.getSelection().index, "video", url);
            } catch (err) {
              console.log(err);
            } finally {
              that.loading = false;
            }
    
            // // 这里可以添加上传逻辑,例如使用 FormData 上传到服务器
            // // 但是请注意,直接上传到服务器的代码不在这里展示
    
            // // 如果只是要在编辑器中插入视频,可以直接使用 file URL
            // if (URL && URL.createObjectURL && type === "video") {
            //   console.log(URL.createObjectURL(file));
            //   console.log(that.$refs);
            //   that.$refs.myQuillEditor.quill.insertEmbed(
            //     that.$refs.myQuillEditor.quill.getSelection().index,
            //     "video",
            //     URL.createObjectURL(file)
            //   );
            // }
          };
        },
      },
    };
    </script>
    <style lang="less" scoped>
    /deep/.ql-editor {
      height: 100px;
    }
    /deep/.ql-snow .ql-picker.ql-size .ql-picker-label::before,
    /deep/.ql-snow .ql-picker.ql-size .ql-picker-item::before {
      content: "14px";
    }
    
    /deep/.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="small"]::before,
    /deep/.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="small"]::before {
      content: "10px";
    }
    /deep/.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="large"]::before,
    /deep/.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="large"]::before {
      content: "18px";
    }
    /deep/.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="huge"]::before,
    /deep/.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="huge"]::before {
      content: "32px";
    }
    
    /deep/.ql-snow .ql-picker.ql-header .ql-picker-label::before,
    /deep/.ql-snow .ql-picker.ql-header .ql-picker-item::before {
      content: "文本";
    }
    /deep/.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="1"]::before,
    /deep/.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="1"]::before {
      content: "标题1";
    }
    /deep/.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="2"]::before,
    /deep/.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="2"]::before {
      content: "标题2";
    }
    /deep/.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="3"]::before,
    /deep/.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="3"]::before {
      content: "标题3";
    }
    /deep/.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="4"]::before,
    /deep/.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="4"]::before {
      content: "标题4";
    }
    /deep/.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="5"]::before,
    /deep/.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="5"]::before {
      content: "标题5";
    }
    /deep/.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="6"]::before,
    /deep/.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="6"]::before {
      content: "标题6";
    }
    
    /deep/.ql-snow .ql-picker.ql-font .ql-picker-label::before,
    /deep/.ql-snow .ql-picker.ql-font .ql-picker-item::before {
      content: "标准字体";
    }
    /deep/.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="serif"]::before,
    /deep/.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="serif"]::before {
      content: "衬线字体";
    }
    /deep/.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="monospace"]::before,
    /deep/.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="monospace"]::before {
      content: "等宽字体";
    }
    </style>
    
    

    3、使用

    <template>
      <Editor v-model="content" />
    </template>
    <script>
    import Editor from "@/components/Editor";
    export default {
      components: {  Editor },
      data(){
          content:''
      }
    }
    </script>
    

    参考文档

    https://www.wangeditor.com/
    https://blog.csdn.net/m0_57442975/article/details/134261247
    https://www.jianshu.com/p/9d0aba0ff8ae

    相关文章

      网友评论

          本文标题:vue2使用富文本编辑器

          本文链接:https://www.haomeiwen.com/subject/blodcjtx.html