第三篇. vue中使用vue-quill-editor富文本插件,图片上传,视频上传

1.安装
vue-quill-editor github地址:https://github.com/surmon-china/vue-quill-editor
官方文档地址:https://www.npmjs.com/package/vue-quill-editor
基于Quill、适用于Vue2的富文本编辑器,支持服务端渲染和单页应用

npm install vue-quill-editor --save

安装图片拖动和变化大小的插件,需要在vue.config.js引入webpack中配置 不配置会出错,具体链接(https://github.com/kensnyder/quill-image-resize-module/issues/54)
plugins: [
    new webpack.ProvidePlugin({
        'window.Quill': 'quill/dist/quill.js',
        'Quill': 'quill/dist/quill.js',
    }),
]
2.局部引入
import Vue from 'vue'
import 'quill/dist/quill.core.css'
import 'quill/dist/quill.snow.css'
import 'quill/dist/quill.bubble.css'
import { quillEditor } from 'vue-quill-editor'
import Quill from 'quill'
import { ImageDrop } from 'quill-image-drop-module'  // 图片拖动插件
import ImageResize from 'quill-image-resize-module'  // 图片设置大小插件
Quill.register('modules/imageDrop', ImageDrop)       // 图片拖动插件
Quill.register('modules/imageResize', ImageResize)   // 图片设置大小插件
// 鼠标移入显示title文字
import { addQuillTitle } from '@/assets/quill-title.js'
Vue.use(quillEditor)
// 图片上传接口
import { richTextImgUpload } from '@/api/uploadFIle'
3.工具栏配置
// 工具栏配置
const toolbarOptions = [
  ['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'] // 上传图片、上传视频
]
/* 富文本编辑图片上传配置*/
const uploadConfig = {
  action: '', // 必填参数 图片上传地址
  methods: 'POST', // 必填参数 图片上传方式
  token: '', // 可选参数 如果需要token验证,假设你的token有存放在sessionStorage
  name: 'img', // 必填参数 文件的参数名
  size: 500, // 可选参数   图片大小,单位为Kb, 1M = 1024Kb
  accept: 'image/png, image/gif, image/jpeg, image/bmp, image/x-icon' // 可选 可上传的图片格式
}
4.data中初始化配置
data() {
    return {
      content: '',
      videoOrimg:true,
      editorOption: {
        placeholder: '请输入...',
        modules: {
          imageResize: {}, //图片拖动设置大小
          imageDrop: true, // 图片拖动
          toolbar: {
            container: toolbarOptions, //工具栏
            handlers: {
              image: (value) => {
                if (value) {
                  // 这是是为了获取你当前点击的那个富文本框
                  this.videoOrimg = true
                  document.querySelectorAll('.upload-demo input')[0].click()
                } else {
                  this.quill.format('image', false)
                }
              },
              video: (value) => {
                if (value) {
                  // 这是是为了获取你当前点击的那个富文本框
                  this.videoOrimg = false
                  document.querySelectorAll('.upload-demo input')[0].click()
                } else {
                  this.quill.format('image', false)
                }
              }
            }
          }
        },
        theme: 'snow'
      }
    }
  },
5.模板中使用
<template>
  <div>
    <el-upload
      class="upload-demo"
      action="#"
      name="file"
      :http-request="requestUpload"
      :before-upload="beforeAvatarUpload"
      :on-success="handleSuccess"
      multiple
    />
    <quill-editor ref="toref" v-model="content" :options="editorOption"  />
  </div>
</template>
6.图片上传(视频上传同理)
因为是前后端分离的,富文本上传图片要单独上传,在content中替换为后端返回图片地址。
 methods: {
    // 覆盖默认的上传行为
    requestUpload(params) {
      const formData = new FormData()
      formData.append('img', params.file)
       // 图片
      if(this.videoOrimg){
        richTextImgUpload(formData).then((res) => {
          params.onSuccess(res)
        })
      }else{
        richTextVideoUpload(formData).then((res) => {
          params.onSuccess(res)
        })
      }
      
    },
    // 判断图片后缀
    beforeAvatarUpload(file) {
      console.log(file,'dasda')
      const isJPG = file.type === 'image/jpeg' || 'image/png'
      const isVideo = file.type === 'video/mp4'
      const isLt2M = file.size / 1024 / 1024 < 10
      // 图片
      if(this.videoOrimg){
        if (!isJPG) {
          this.$message.error('上传图片只能是 JPG , PNG格式!')
        }
        if (!isLt2M) {
          this.$message.error('上传图片大小不能超过 10MB!')
        }
         return isJPG && isLt2M
      }else{
          if(!isVideo){
            this.$message.error('上传视频只能是 MP4格式!')
          }
          return isVideo
      }
     
    },
    // 上传成功
    handleSuccess(res, file) {
      if (res.error == 0) {
        // 动态添加 ref  通过 eval () 去执行
        const toeval = this.$refs.toref.quill
        // eval() 函数可计算某个字符串,并执行其中的的 JavaScript 代码。
        // 获取光标所在位置
        const length = toeval.selection.savedRange.index
        // 插入图片,res为服务器返回的图片链接地址
         // 图片
      if(this.videoOrimg){
        toeval.insertEmbed(
          length,
          'image',
          process.env.VUE_APP_BASE_API_ORIGIN + res.data.imgscr
        )
      }else{
        toeval.insertEmbed(
          length,
          'video',
          process.env.VUE_APP_BASE_API_ORIGIN + res.data.imgscr
        )
      }
        // 调整光标到最后
        toeval.setSelection(length + 1)
      }
    },
    // 将内容上传给父组件
    postContent() {
      this.$emit('getContent', this.content)
    },
  },
7.quill-title.js内容
const titleConfig = {
    'ql-bold':'加粗',
    'ql-color':'颜色',
    'ql-font':'字体',
    'ql-code':'插入代码',
    'ql-italic':'斜体',
    'ql-link':'添加链接',
    'ql-background':'背景颜色',
    'ql-size':'字体大小',
    'ql-strike':'删除线',
    'ql-script':'上标/下标',
    'ql-underline':'下划线',
    'ql-blockquote':'引用',
    'ql-header':'标题',
    'ql-indent':'缩进',
    'ql-list':'列表',
    'ql-align':'文本对齐',
    'ql-direction':'文本方向',
    'ql-code-block':'代码块',
    'ql-formula':'公式',
    'ql-image':'图片',
    'ql-video':'视频',
    'ql-clean':'清除字体样式'
  };
   
  export function addQuillTitle(){
    const oToolBar = document.querySelector('.ql-toolbar'),
          aButton = oToolBar.querySelectorAll('button'),
          aSelect =  oToolBar.querySelectorAll('select');
    aButton.forEach(function(item){
      if(item.className === 'ql-script'){
        item.value === 'sub' ? item.title = '下标': item.title = '上标';
      }else if(item.className === 'ql-indent'){
        item.value === '+1' ? item.title ='向右缩进': item.title ='向左缩进';
      }else{
        item.title = titleConfig[item.classList[0]];
      }
    });
    aSelect.forEach(function(item){
      item.parentNode.title = titleConfig[item.classList[0]];
    });
  }
8.完整代码
<template>
  <div>
    <el-upload
      class="upload-demo"
      action="#"
      name="file"
      :http-request="requestUpload"
      :before-upload="beforeAvatarUpload"
      :on-success="handleSuccess"
      multiple
    />
    <quill-editor ref="toref" v-model="content" :options="editorOption"  />
  </div>
</template>

<script>
import Vue from 'vue'
import 'quill/dist/quill.core.css'
import 'quill/dist/quill.snow.css'
import 'quill/dist/quill.bubble.css'
import { quillEditor } from 'vue-quill-editor'
import Quill from 'quill'
import { ImageDrop } from 'quill-image-drop-module'  // 图片拖动插件
import ImageResize from 'quill-image-resize-module'  // 图片设置大小插件
Quill.register('modules/imageDrop', ImageDrop)       // 图片拖动插件
Quill.register('modules/imageResize', ImageResize)   // 图片设置大小插件
// 鼠标移入显示title文字
import { addQuillTitle } from '@/assets/quill-title.js'
Vue.use(quillEditor)
// 图片上传接口
import { richTextImgUpload, richTextVideoUpload } from '@/api/uploadFIle'
// 工具栏配置
const toolbarOptions = [
  ['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'] // 上传图片、上传视频
]
/* 富文本编辑图片上传配置*/
const uploadConfig = {
  action: '', // 必填参数 图片上传地址
  methods: 'POST', // 必填参数 图片上传方式
  token: '', // 可选参数 如果需要token验证,假设你的token有存放在sessionStorage
  name: 'img', // 必填参数 文件的参数名
  size: 500, // 可选参数   图片大小,单位为Kb, 1M = 1024Kb
  accept: 'image/png, image/gif, image/jpeg, image/bmp, image/x-icon' // 可选 可上传的图片格式
}
export default {
  components: {
    quillEditor
  },
  props: {
    contents:String,
    default:''
  },
  data() {
    return {
      content: '',
      videoOrimg:true,
      editorOption: {
        placeholder: '请输入...',
        modules: {
          imageResize: {}, //图片拖动设置大小
          imageDrop: true, // 图片拖动
          toolbar: {
            container: toolbarOptions, //工具栏
            handlers: {
              image: (value) => {
                if (value) {
                  // 这是是为了获取你当前点击的那个富文本框
                  this.videoOrimg = true
                  document.querySelectorAll('.upload-demo input')[0].click()
                } else {
                  this.quill.format('image', false)
                }
              },
              video: (value) => {
                if (value) {
                  // 这是是为了获取你当前点击的那个富文本框
                  this.videoOrimg = false
                  document.querySelectorAll('.upload-demo input')[0].click()
                } else {
                  this.quill.format('image', false)
                }
              }
            }
          }
        },
        theme: 'snow'
      }
    }
  },
  mounted() {
    addQuillTitle()
  },
  methods: {
    // 覆盖默认的上传行为
    requestUpload(params) {
      const formData = new FormData()
      formData.append('img', params.file)
       // 图片
      if(this.videoOrimg){
        richTextImgUpload(formData).then((res) => {
          params.onSuccess(res)
        })
      }else{
        richTextVideoUpload(formData).then((res) => {
          params.onSuccess(res)
        })
      }
      
    },
    // 判断图片后缀
    beforeAvatarUpload(file) {
      console.log(file,'dasda')
      const isJPG = file.type === 'image/jpeg' || 'image/png'
      const isVideo = file.type === 'video/mp4'
      const isLt2M = file.size / 1024 / 1024 < 10
      // 图片
      if(this.videoOrimg){
        if (!isJPG) {
          this.$message.error('上传图片只能是 JPG , PNG格式!')
        }
        if (!isLt2M) {
          this.$message.error('上传图片大小不能超过 10MB!')
        }
         return isJPG && isLt2M
      }else{
          if(!isVideo){
            this.$message.error('上传视频只能是 MP4格式!')
          }
          return isVideo
      }
    },
    // 上传成功
    handleSuccess(res, file) {
      if (res.error == 0) {
        // 动态添加 ref  通过 eval () 去执行
        const toeval = this.$refs.toref.quill
        // eval() 函数可计算某个字符串,并执行其中的的 JavaScript 代码。
        // 获取光标所在位置
        const length = toeval.selection.savedRange.index
        // 插入图片,res为服务器返回的图片链接地址
         // 图片
      if(this.videoOrimg){
        toeval.insertEmbed(
          length,
          'image',
          process.env.VUE_APP_BASE_API_ORIGIN + res.data.imgscr
        )
      }else{
        toeval.insertEmbed(
          length,
          'video',
          process.env.VUE_APP_BASE_API_ORIGIN + res.data.imgscr
        )
      }
        // 调整光标到最后
        toeval.setSelection(length + 1)
      }
    },
    // 将内容上传给父组件
    postContent() {
      this.$emit('getContent', this.content)
    },
  },
  watch: {
    contents:{
        immediate: true,    // 这句重要
        handler (val) {
            this.content = this.contents
        }
    }
  }
}
</script>

<style scoped>
.upload-demo {
  display: none;
}
</style>

9.预览

posted @ 2021-03-06 11:18  Ananiah  阅读(3629)  评论(5编辑  收藏  举报