🚀 本章主要介绍在Vue中使用quill-editor富文本插件,支持图片的放大缩小及拖动

效果图:

在这里插入图片描述

1、下载依赖
cnpm i vue-quill-editor --save
cnpm i quill-image-resize-module --save        //图片操作
2、全局引入及注册main.js
import VueQuillEditor from 'vue-quill-editor';
import * as Quill from 'quill'; //引入编辑器
import resizeImage from 'quill-image-resize-module'; // 图片缩放组件。
Quill.register('modules/resizeImage ', resizeImage);
import 'quill/dist/quill.core.css';
import 'quill/dist/quill.snow.css';
import 'quill/dist/quill.bubble.css';
Vue.use(VueQuillEditor);
3、封装组件RichText
<template>
  <div class="richBox" v-loading="spinning">
    <quill-editor
        v-model="content"
        :options="editorOption"
        ref="QuillEditor">
    </quill-editor>
     <input type="file"
      ref="imgs"
      accept="image/*" class="uploads" style="display: none;" @change="uploadImgs">
      <input type="file"
       ref="videos"
       accept="video/*" class="upVideo" style="display: none;" @change="uploadVideo">
  </div>
</template>

<script>
 import {
   uploads
 } from "./upload.js"          //uploads.js是封装的一个上传方法,可基于Promise进行封装
 const toolbarOptions = [
        ['bold', 'italic', 'underline', 'strike'],        // toggled buttons
        ['blockquote', 'code-block'],

        [{'header': 1}, {'header': 2}],               // custom button values
        [{'list': 'ordered'}, {'list': 'bullet'}],
        [{'script': 'sub'}, {'script': 'super'}],      // superscript/subscript
        [{'indent': '-1'}, {'indent': '+1'}],          // outdent/indent
        [{'direction': 'rtl'}],                         // text direction

        [{'size': ['small', false, 'large', 'huge']}],  // custom dropdown
        [{'header': [1, 2, 3, 4, 5, 6, false]}],

        [{'color': []}, {'background': []}],          // dropdown with defaults from theme
        [{'font': []}],
        [{'align': []}],
        ['link', 'image', 'video'],
        ['clean']                                         // remove formatting button
      ]
  export default{
    props: {
       values: {                          //用于回显
         type: String,
         default: ''
       },
    },
    data(){
      return{
        spinning:false,
        content: '',
        editorOption: {
          placeholder:"请输入",
          modules: {
            imageResize: {                       //图片放大缩小配置 
              displayStyles: {
                backgroundColor: 'black',
                border: 'none',
                color: 'white'
              },
              modules: ['Resize', 'DisplaySize', 'Toolbar']
            },
            toolbar: {
              container: toolbarOptions,  // 工具栏
              handlers: {
                'image': function (value) {
                    if (value) {
                      document.querySelector('.uploads').click()
                    } else {
                        this.quill.format('image', false);
                    }
                },
                'video':function(value){
                  if (value) {
                    document.querySelector('.upVideo').click()
                  } else {
                     this.quill.format('video', false);
                  }
                }
              }
            }
          }
        }
      }
    },
    watch: {                        //监听回显的数据变化
        values: {
         handler(newVal, oldVal) {
            this.content = newVal;
              this.$refs.QuillEditor.quill.blur();
         },
          immediate: true
        }
     },
    methods:{
      getVal () {                     //返回内容
        return this.content
      },
      setVal(data){             //赋值
        this.content = data;
      },
      uploadImgs(e){            //上传图片
        var file = this.$refs.imgs.files[0];
        this.spinning = true
        this.upFile(file,'image');
        e.target.value = '';
      },
      uploadVideo(e){              //上传视频
        var file = this.$refs.videos.files[0];
        this.spinning = true
        this.upFile(file,'video')
      },
      upFile(file,type){               //上传api
        uploads(file).then(result => {
          this.spinning = false
          this.insertImg(result,type)
        })
      },
      insertImg(url,type){         //插入图片
        var quill = this.$refs.QuillEditor.quill;
        let length = quill.getSelection().index;
        quill.insertEmbed(length,type,url);
        quill.setSelection(length+1);
      }
    }
  }
</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: "文本" !important;
  }
  .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" !important;
  }
  .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" !important;
  }
  .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" !important;
  }
  .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" !important;
  }
  .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" !important;
  }
  .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" !important;
  }

  .ql-snow .ql-picker.ql-font .ql-picker-label::before,
  .ql-snow .ql-picker.ql-font .ql-picker-item::before {
    content: "标准字体" !important;
  }
  .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: "衬线字体" !important;
  }
  .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: "等宽字体" !important;
  }
</style>
<style scoped="scoped" lang="scss">
.richBox{
  width: 95% !important;
  .quill-editor{
    width: 100% !important;
    height: 600px;
  }
}
::v-deep .ql-container{
  height: 90% !important;
}

</style>

4、使用
 <richTxt ref="child" :values="form.content"/>

1、获取富文本内容:
let oldProcedure = this.$refs.child.getVal();
this.form.content= oldProcedure;

5、万事俱备之后,运行项目可能会出现imports错误,这里提供了cli2和cli3两种解决方案

1. 在vue cli2中,处理方案如下:
找到webpack.base.conf文件,添加以下代码

const webpack = require('webpack');
module.exports = {
	plugins: [
    new webpack.ProvidePlugin({
      'window.Quill': 'quill/dist/quill.js',
      'Quill': 'quill/dist/quill.js'
    })
  ],
}

2.在vue cli3中,处理方案如下:
在项目根目录找到vue.config.js文件,如果没有就创建此文件,添加以下代码

const webpack = require('webpack')
module.exports = {
  chainWebpack: config => {
  	//富文本图片缩放
    config.plugin('provide').use(webpack.ProvidePlugin, [{
      'window.Quill': 'quill',
      'Quill': 'quill/dist/quill.js'
    }])
  }
}
//注意  如果原文件有chainWebpack 不要重复添加,在原有chainWebpack里面的最后面添加上面代码
6、格式问题

v-html渲染格式问题:给v-html绑定的元素添加class="ql-editor"

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐