vue2+quill封装富文本编辑器

vue2封装富文本编辑器

下载依赖

npm install quill@1.3.7
npm install quill-image-drop-module@1.0.3
npm install quill-image-extend-module@1.1.2
npm install quill-image-resize-module@3.0.0
npm install vue-quill-editor@3.0.6

简单使用

<template>
  <div>
    <div>
      <!--富文本编辑器组件-->
      <quill-editor
          v-model="formData.content"
          ref="QuillEditor"
          class="editor"
          :options="editorOption"
          @blur="onEditorBlur($event)"
          @focus="onEditorFocus($event)"
          @ready="onEditorReady($event)"
      >
      </quill-editor>
    </div>
  </div>
</template>
<script>
  import { quillEditor } from 'vue-quill-editor'
  import Delta from 'quill-delta'
  import 'quill/dist/quill.core.css';
  import 'quill/dist/quill.snow.css';
  import 'quill/dist/quill.bubble.css';
  import * as Quill from 'quill' //引入编辑器

  const toolbarOptions = [
    ['bold', 'italic', 'underline', 'strike'],        // 加粗,斜体,下划线,删除线
    ['blockquote', 'code-block'],                     //引用,代码块
    // [{ 'header': 1 }, { 'header': 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': ['SimSun', 'SimHei', 'Microsoft-YaHei', 'KaiTi', 'FangSong', 'Arial'] }], // 字体
    [{ 'align': [] }],    // 居中
    ['clean'],            // 清除样式,
    ['link','image'],   // 上传图片、上传视频
    ['myButton'],
  ]

  // toolbar标题
  const titleConfig = [
    { Choice: '.ql-insertMetric', title: '跳转配置' },
    { Choice: '.ql-bold', title: '加粗' },
    { Choice: '.ql-italic', title: '斜体' },
    { Choice: '.ql-underline', title: '下划线' },
    { Choice: '.ql-header', title: '段落格式' },
    { Choice: '.ql-strike', title: '删除线' },
    { Choice: '.ql-blockquote', title: '块引用' },
    { Choice: '.ql-code', title: '插入代码' },
    { Choice: '.ql-code-block', title: '插入代码段' },
    { Choice: '.ql-font', title: '字体' },
    { Choice: '.ql-size', title: '字体大小' },
    { Choice: '.ql-list[value="ordered"]', title: '编号列表' },
    { Choice: '.ql-list[value="bullet"]', title: '项目列表' },
    { Choice: '.ql-direction', title: '文本方向' },
    { Choice: '.ql-header[value="1"]', title: 'h1' },
    { Choice: '.ql-header[value="2"]', title: 'h2' },
    { Choice: '.ql-align', title: '对齐方式' },
    { Choice: '.ql-color', title: '字体颜色' },
    { Choice: '.ql-background', title: '背景颜色' },
    { Choice: '.ql-image', title: '图像' },
    { Choice: '.ql-video', title: '视频' },
    { Choice: '.ql-link', title: '添加链接' },
    { Choice: '.ql-formula', title: '插入公式' },
    { Choice: '.ql-clean', title: '清除字体格式' },
    { Choice: '.ql-script[value="sub"]', title: '下标' },
    { Choice: '.ql-script[value="super"]', title: '上标' },
    { Choice: '.ql-indent[value="-1"]', title: '向左缩进' },
    { Choice: '.ql-indent[value="+1"]', title: '向右缩进' },
    { Choice: '.ql-header .ql-picker-label', title: '标题大小' },
    { Choice: '.ql-header .ql-picker-item[data-value="1"]', title: '标题一' },
    { Choice: '.ql-header .ql-picker-item[data-value="2"]', title: '标题二' },
    { Choice: '.ql-header .ql-picker-item[data-value="3"]', title: '标题三' },
    { Choice: '.ql-header .ql-picker-item[data-value="4"]', title: '标题四' },
    { Choice: '.ql-header .ql-picker-item[data-value="5"]', title: '标题五' },
    { Choice: '.ql-header .ql-picker-item[data-value="6"]', title: '标题六' },
    { Choice: '.ql-header .ql-picker-item:last-child', title: '标准' },
    { Choice: '.ql-size .ql-picker-item[data-value="small"]', title: '小号' },
    { Choice: '.ql-size .ql-picker-item[data-value="large"]', title: '大号' },
    { Choice: '.ql-size .ql-picker-item[data-value="huge"]', title: '超大号' },
    { Choice: '.ql-size .ql-picker-item:nth-child(2)', title: '标准' },
    { Choice: '.ql-align .ql-picker-item:first-child', title: '居左对齐' },
    { Choice: '.ql-align .ql-picker-item[data-value="center"]', title: '居中对齐' },
    { Choice: '.ql-align .ql-picker-item[data-value="right"]', title: '居右对齐' },
    { Choice: '.ql-align .ql-picker-item[data-value="justify"]', title: '两端对齐' }
  ]
  export default {
    name: 'addarticle',
    components: {
      quillEditor
    },
    data () {
      return {
        formData: {
          content: '' // `<h1 style="text-align: center;">Welcome to the TinyMCE demo!</h1>`
        },
        editorOption: {
          placeholder: '请在这里输入',
          theme: 'snow', //主题 snow/bubble
          modules: {
            history: {
              delay: 1000,
              maxStack: 50,
              userOnly: false
            },
            toolbar: {
              container: toolbarOptions,
              handlers: {}
            }
          }
        }
      }
    },
    mounted () {
      this.initTitle()
    },
    methods: {
      initTitle () {
        document.getElementsByClassName('ql-editor')[0].dataset.placeholder = ''
        for (let item of titleConfig) {
          let tip = document.querySelector('.quill-editor ' + item.Choice)
          if (!tip) continue
          tip.setAttribute('title', item.title)
        }
      },

      // 失去焦点
      onEditorBlur (editor) { },

      // 获得焦点
      onEditorFocus (editor) {
      },

      // 开始
      onEditorReady (editor) { },
    }
  }
</script>
<style>
</style>

汉化标题栏

<style>
    p {
      margin: 10px;
    }

    .edit_container,
    .quill-editor {
      height: 300px;
    }

    .ql-snow .ql-picker.ql-size .ql-picker-label::before,
    .ql-snow .ql-picker.ql-size .ql-picker-item::before {
      content: "14px";
    }

    .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="small"]::before,
    .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="small"]::before {
      content: "10px";
    }
    .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="large"]::before,
    .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="large"]::before {
      content: "18px";
    }
    .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="huge"]::before,
    .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="huge"]::before {
      content: "32px";
    }

    .ql-snow .ql-picker.ql-header .ql-picker-label::before,
    .ql-snow .ql-picker.ql-header .ql-picker-item::before {
      content: "文本";
    }
    .ql-snow .ql-picker.ql-header .ql-picker-label[data-value="1"]::before,
    .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="1"]::before {
      content: "标题1";
    }
    .ql-snow .ql-picker.ql-header .ql-picker-label[data-value="2"]::before,
    .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="2"]::before {
      content: "标题2";
    }
    .ql-snow .ql-picker.ql-header .ql-picker-label[data-value="3"]::before,
    .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="3"]::before {
      content: "标题3";
    }
    .ql-snow .ql-picker.ql-header .ql-picker-label[data-value="4"]::before,
    .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="4"]::before {
      content: "标题4";
    }
    .ql-snow .ql-picker.ql-header .ql-picker-label[data-value="5"]::before,
    .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="5"]::before {
      content: "标题5";
    }
    .ql-snow .ql-picker.ql-header .ql-picker-label[data-value="6"]::before,
    .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="6"]::before {
      content: "标题6";
    }

    .ql-snow .ql-picker.ql-font .ql-picker-label::before,
    .ql-snow .ql-picker.ql-font .ql-picker-item::before {
      content: "标准字体";
    }
    .ql-snow .ql-picker.ql-font .ql-picker-label[data-value="serif"]::before,
    .ql-snow .ql-picker.ql-font .ql-picker-item[data-value="serif"]::before {
      content: "衬线字体";
    }
    .ql-snow .ql-picker.ql-font .ql-picker-label[data-value="monospace"]::before,
    .ql-snow .ql-picker.ql-font .ql-picker-item[data-value="monospace"]::before {
      content: "等宽字体";
    }
</style>

图片拖拽上传和调整大小

  import { ImageDrop } from 'quill-image-drop-module';
  import ImageResize from "quill-image-resize-module";
  Quill.register("modules/imageResize", ImageResize);
  import {container, ImageExtend, QuillWatch} from 'quill-image-extend-module'
  Quill.register('modules/ImageExtend', ImageExtend)
  Quill.register('modules/imageDrop', ImageDrop);
          modules: {
            history: {
              delay: 1000,
              maxStack: 50,
              userOnly: false
            },
            toolbar: {
              container: toolbarOptions,
              handlers: {
              }
            },
            // 图片拖拽上传
            imageDrop:true,
            // 放大缩小
            imageResize:{
              displaySize: true
            },
          }

解决resize的报错

vue-cli3

const webpack = require("webpack");
module.exports = {
  //调整内部的 webpack 配置
  configureWebpack: {
    plugins: [
      new webpack.ProvidePlugin({
        'window.Quill': 'quill/dist/quill.js',
        Quill: 'quill/dist/quill.js'
      })
    ]
  },
}

vue-cli4

const { defineConfig } = require('@vue/cli-service')
const webpack = require('webpack');

module.exports = {
  transpileDependencies: true,
  chainWebpack: (config) => {
    config.plugin('provide').use(new webpack.ProvidePlugin({
      'window.Quill': 'quill/dist/quill.js',
      Quill: 'quill/dist/quill.js'
    }));
  }
};

上传如果不想走接口的小伙伴到这就可以了~~~

===========================================================================

视频中的一点和笔记的出入

myUoload = 笔记中的myButton

myMethod = 笔记中的showHandle

自定义上传

  • 引入uoload组件
<el-upload
    class="quill-upload"
    action="http://localhost:9090/file/upload"
    :headers="{'token':getToken()}"
    :before-upload="beforeUpload"
    :on-success="quillSuccess"
    ref="upload"
>
</el-upload>
  • 配置项
 toolbar: {
    container: toolbarOptions,
    handlers: {
      myUploadBtn: this.showHandle
    }
},
  • 写以下三个方法
showHandle () {
  // this.$message.success('这是自定义工具栏的方法!')
  // 获取到Quill实例
  this.Quill=this.$refs.QuillEditor.quill
  this.$refs.upload.$children[0].$refs.input.click()
},

// 自定义按钮内容初始化
initButton () {
  const editorButton = document.querySelector('.ql-myButton')
  editorButton.innerHTML = '<i class="el-icon-picture" style="font-size: 18px;color:black"></i>'
},

// 上传成功的回调
quillSuccess(res, file) {
  if (file.status === 'success') {
    // 获取光标所在位置
    let length = this.$refs.QuillEditor.quill.getSelection().index
    // 插入图片  res.url为服务器返回的图片地址
    this.Quill.insertEmbed(length, 'image', res)
    // 调整光标到最后
    this.$refs.QuillEditor.quill.setSelection(length + 1)
  } else {
    this.$message.error('图片插入失败')
  }
},      
  • 挂载时调用方法
mounted () {
  this.initButton()
  this.initTitle()
},

完整代码

<template>
  <div>
    <div>
      <!--富文本编辑器组件-->
      <quill-editor
          v-model="formData.content"
          ref="QuillEditor"
          class="editor"
          :options="editorOption"
          @blur="onEditorBlur($event)"
          @focus="onEditorFocus($event)"
          @ready="onEditorReady($event)"
      >
      </quill-editor>

        // action自行更换成自己的上传地址
        // headers的token入股偶有的话也需要自己

      <el-upload
          class="quill-upload"
          action="http://localhost:9090/file/upload"
          :headers="{'token':getToken()}"
          :before-upload="beforeUpload"
          :on-success="quillSuccess"
          ref="upload"
      >
      </el-upload>
    </div>
  </div>
</template>
<script>
  import { quillEditor } from 'vue-quill-editor'
  import Delta from 'quill-delta'
  import 'quill/dist/quill.core.css';
  import 'quill/dist/quill.snow.css';
  import 'quill/dist/quill.bubble.css';
  import * as Quill from 'quill' //引入编辑器
  import { ImageDrop } from 'quill-image-drop-module';
  import ImageResize from "quill-image-resize-module";
  Quill.register("modules/imageResize", ImageResize);
  import {container, ImageExtend, QuillWatch} from 'quill-image-extend-module'
  Quill.register('modules/ImageExtend', ImageExtend)
  Quill.register('modules/imageDrop', ImageDrop);

  const toolbarOptions = [
    ['bold', 'italic', 'underline', 'strike'],        // 加粗,斜体,下划线,删除线
    ['blockquote', 'code-block'],                     //引用,代码块
    // [{ 'header': 1 }, { 'header': 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': ['SimSun', 'SimHei', 'Microsoft-YaHei', 'KaiTi', 'FangSong', 'Arial'] }], // 字体
    [{ 'align': [] }],    // 居中
    ['clean'],            // 清除样式,
    ['link'],   // 上传图片、上传视频
    ['myButton'],
  ]

  // toolbar标题
  const titleConfig = [
    { Choice: '.ql-insertMetric', title: '跳转配置' },
    { Choice: '.ql-bold', title: '加粗' },
    { Choice: '.ql-italic', title: '斜体' },
    { Choice: '.ql-underline', title: '下划线' },
    { Choice: '.ql-header', title: '段落格式' },
    { Choice: '.ql-strike', title: '删除线' },
    { Choice: '.ql-blockquote', title: '块引用' },
    { Choice: '.ql-code', title: '插入代码' },
    { Choice: '.ql-code-block', title: '插入代码段' },
    { Choice: '.ql-font', title: '字体' },
    { Choice: '.ql-size', title: '字体大小' },
    { Choice: '.ql-list[value="ordered"]', title: '编号列表' },
    { Choice: '.ql-list[value="bullet"]', title: '项目列表' },
    { Choice: '.ql-direction', title: '文本方向' },
    { Choice: '.ql-header[value="1"]', title: 'h1' },
    { Choice: '.ql-header[value="2"]', title: 'h2' },
    { Choice: '.ql-align', title: '对齐方式' },
    { Choice: '.ql-color', title: '字体颜色' },
    { Choice: '.ql-background', title: '背景颜色' },
    { Choice: '.ql-image', title: '图像' },
    { Choice: '.ql-video', title: '视频' },
    { Choice: '.ql-link', title: '添加链接' },
    { Choice: '.ql-formula', title: '插入公式' },
    { Choice: '.ql-clean', title: '清除字体格式' },
    { Choice: '.ql-script[value="sub"]', title: '下标' },
    { Choice: '.ql-script[value="super"]', title: '上标' },
    { Choice: '.ql-indent[value="-1"]', title: '向左缩进' },
    { Choice: '.ql-indent[value="+1"]', title: '向右缩进' },
    { Choice: '.ql-header .ql-picker-label', title: '标题大小' },
    { Choice: '.ql-header .ql-picker-item[data-value="1"]', title: '标题一' },
    { Choice: '.ql-header .ql-picker-item[data-value="2"]', title: '标题二' },
    { Choice: '.ql-header .ql-picker-item[data-value="3"]', title: '标题三' },
    { Choice: '.ql-header .ql-picker-item[data-value="4"]', title: '标题四' },
    { Choice: '.ql-header .ql-picker-item[data-value="5"]', title: '标题五' },
    { Choice: '.ql-header .ql-picker-item[data-value="6"]', title: '标题六' },
    { Choice: '.ql-header .ql-picker-item:last-child', title: '标准' },
    { Choice: '.ql-size .ql-picker-item[data-value="small"]', title: '小号' },
    { Choice: '.ql-size .ql-picker-item[data-value="large"]', title: '大号' },
    { Choice: '.ql-size .ql-picker-item[data-value="huge"]', title: '超大号' },
    { Choice: '.ql-size .ql-picker-item:nth-child(2)', title: '标准' },
    { Choice: '.ql-align .ql-picker-item:first-child', title: '居左对齐' },
    { Choice: '.ql-align .ql-picker-item[data-value="center"]', title: '居中对齐' },
    { Choice: '.ql-align .ql-picker-item[data-value="right"]', title: '居右对齐' },
    { Choice: '.ql-align .ql-picker-item[data-value="justify"]', title: '两端对齐' }
  ]
  export default {
    name: 'addarticle',
    components: {
      quillEditor
    },
    data () {
      return {
        uploadUrl: 'http://localhost:9090/file/upload', // 上传的图片服务器地址
        headers: {
          Authorization: 'Bearer ' + this.getToken(),
        },
        formData: {
          content: '' // `<h1 style="text-align: center;">Welcome to the TinyMCE demo!</h1>`
        },
        Quill: null,
        editorOption: {
          placeholder: '请在这里输入',
          theme: 'snow', //主题 snow/bubble
          modules: {
            history: {
              delay: 1000,
              maxStack: 50,
              userOnly: false
            },
            toolbar: {
              container: toolbarOptions,
              handlers: {
                myButton: this.showHandle,
              }
            },
            // 图片拖拽上传
            imageDrop:true,
            // 放大缩小
            imageResize:{
              displaySize: true
            },
          }
        }
      }
    },
    mounted () {
      this.initButton()
      this.initTitle()
    },
    methods: {
      getToken() {
        if (localStorage.getItem("userInfo")) {
          return JSON.parse(localStorage.getItem("userInfo")).token
        }
      },

      initTitle () {
        document.getElementsByClassName('ql-editor')[0].dataset.placeholder = ''
        for (let item of titleConfig) {
          let tip = document.querySelector('.quill-editor ' + item.Choice)
          if (!tip) continue
          tip.setAttribute('title', item.title)
        }
      },

      showHandle () {
        // this.$message.success('这是自定义工具栏的方法!目前没有功能哦')
        // 获取到Quill实例
        this.Quill=this.$refs.QuillEditor.quill
        this.$refs.upload.$children[0].$refs.input.click()
      },

      // 自定义按钮内容初始化
      initButton () {
        const editorButton = document.querySelector('.ql-myButton')
        editorButton.innerHTML = '<i class="el-icon-picture" style="font-size: 18px;color:black"></i>'
      },

      // 失去焦点
      onEditorBlur (editor) { },

      // 获得焦点
      onEditorFocus (editor) {
      },

      // 开始
      onEditorReady (editor) { },

      beforeUpload(res, file) {
        console.log('HRichText upload before')
      },


      quillSuccess(res, file) {
        if (file.status === 'success') {
          // 获取光标所在位置
          let length = this.$refs.QuillEditor.quill.getSelection().index
          // 插入图片  res.url为服务器返回的图片地址
          this.Quill.insertEmbed(length, 'image', res)
          // 调整光标到最后
          this.$refs.QuillEditor.quill.setSelection(length + 1)
        } else {
          this.$message.error('图片插入失败')
        }
      },
    }
  }
</script>

<style>
p {
  margin: 10px;
}

.edit_container,
.quill-editor {
  height: 300px;
}

.ql-snow .ql-picker.ql-size .ql-picker-label::before,
.ql-snow .ql-picker.ql-size .ql-picker-item::before {
  content: "14px";
}

.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="small"]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="small"]::before {
  content: "10px";
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="large"]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="large"]::before {
  content: "18px";
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="huge"]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="huge"]::before {
  content: "32px";
}

.ql-snow .ql-picker.ql-header .ql-picker-label::before,
.ql-snow .ql-picker.ql-header .ql-picker-item::before {
  content: "文本";
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="1"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="1"]::before {
  content: "标题1";
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="2"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="2"]::before {
  content: "标题2";
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="3"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="3"]::before {
  content: "标题3";
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="4"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="4"]::before {
  content: "标题4";
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="5"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="5"]::before {
  content: "标题5";
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="6"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="6"]::before {
  content: "标题6";
}

.ql-snow .ql-picker.ql-font .ql-picker-label::before,
.ql-snow .ql-picker.ql-font .ql-picker-item::before {
  content: "标准字体";
}
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="serif"]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="serif"]::before {
  content: "衬线字体";
}
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="monospace"]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="monospace"]::before {
  content: "等宽字体";
}
</style>
  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值