vue项目里修改Quill内置的video blot,用video标签替换iframe

vue项目里修改Quill内置的video blot,用video标签替换iframe

既然搜到这了,quill的基本安装使用就不多说了,quill内置的video模块是使用iframe标签,用视频网站上视频分享连接没问题的,因为项目上用服务器本地的MP4视频,本来iframe的src直接指.mp4文件也是可以的,其他浏览器都可以,但是还有个感人的IE,iframe里直接指向.mp4时IE会变成下载,只好把iframe改成H5原生的video标签

参考了quill的源码,直接拷贝video.js模块后修改,在vue工程目录下创建quill文件夹及文件:src\quill\video.js

import { Quill } from 'vue-quill-editor'

// 源码中是import直接倒入,这里要用Quill.import引入
const BlockEmbed = Quill.import('blots/block/embed')
const Link = Quill.import('formats/link')

const ATTRIBUTES = ['height', 'width']

class Video extends BlockEmbed {
  static create (value) {
    const node = super.create(value)
    // 添加video标签所需的属性
    node.setAttribute('controls', 'controls')
    node.setAttribute('type', 'video/mp4')
    node.setAttribute('src', this.sanitize(value))
    return node
  }

  static formats (domNode) {
    return ATTRIBUTES.reduce((formats, attribute) => {
      if (domNode.hasAttribute(attribute)) {
        formats[attribute] = domNode.getAttribute(attribute)
      }
      return formats
    }, {})
  }

  static sanitize (url) {
    return Link.sanitize(url) // eslint-disable-line import/no-named-as-default-member
  }

  static value (domNode) {
    return domNode.getAttribute('src')
  }

  format (name, value) {
    if (ATTRIBUTES.indexOf(name) > -1) {
      if (value) {
        this.domNode.setAttribute(name, value)
      } else {
        this.domNode.removeAttribute(name)
      }
    } else {
      super.format(name, value)
    }
  }

  html () {
    const { video } = this.value()
    return `<a href="${video}">${video}</a>`
  }
}
Video.blotName = 'video' // 这里不用改,楼主不用iframe,直接替换掉原来,如果需要也可以保留原来的,这里用个新的blot
Video.className = 'ql-video'
Video.tagName = 'video' // 用video标签替换iframe

export default Video

vue组件中引入quill

<template>
  <div class="post-editor">
    <media-card :fiche="post" @editCover="editCover" editable />
    <quill-editor
      v-model="post.content"
      :options="editorOption"
      style="min-height: 200px; margin-bottom: 54px"
      ref="newEditor"
      @change="onEditorChange($event)">
    </quill-editor>
    <div class="button-box row justify-end">
      <q-btn icon="save" label="保存" color="tpNav" :disable="notValid" @click="savePost" style="padding: 0 2rem;" />
    </div>
    <vue-transmit
      tag="div"
      v-bind="uploadoptions"
      @success="filehandle"
      @error="errhandle"
      @upload-progress="upgress"
      ref="uploader" />
  </div>
</template>

<script>
import { mapState } from 'vuex'
import * as Quill from 'quill'
import 'quill/dist/quill.core.css'
import 'quill/dist/quill.snow.css'
import {quillEditor} from 'vue-quill-editor'
import mediaCard from '../../components/mediacard'

// quill编辑器的字体
var fonts = ['Microsoft-YaHei', 'SimSun', 'SimHei', 'KaiTi', 'FangSong', 'Arial', 'Times-New-Roman', 'sans-serif']
var Font = Quill.import('formats/font')
Font.whitelist = fonts
Quill.register(Font, true)

// 这里引入修改过的video模块并注册
import Video from '../../quill/video'
Quill.register(Video, true)

export default {
  name: 'cmseditor',
  components: {
    quillEditor,
    mediaCard
  },
  props: {
    reportId: {
      type: String,
      default: ''
    }
  },
  data () {
    return {
      saving: false,
      changeCover: false,
      changeDelay: 300,
      delayFlag: true,
      pictures: [],
      uplaodBase: '/api/storage/upload/',
      uploadoptions: {
        acceptedFileTypes: ['image/*'],
        url: '',
        clickable: false,
        headers: {
          Authorization: `Bearer ${this.$store.state.auth.token}`
        }
      },
      progress: 0,
      post: {
        '_id': '',
        title: '',
        date: '',
        cover: '',
        abstract: '',
        attachments: [],
        content: ''
      },
      editorOption: {
        modules: {
          toolbar: [
            ['bold', 'italic', 'underline'],
            ['blockquote'],
            [{ 'list': 'ordered' }, { 'list': 'bullet' }],
            [{ 'script': 'super' }],
            [{ 'indent': '-1' }, { 'indent': '+1' }],
            [{ 'size': ['small', false, 'large', 'huge'] }],
            [{ 'header': [1, 2, 3, 4, 5, 6, false] }],
            [{ 'color': [] }, { 'background': [] }],
            [{ 'font': fonts }],
            [{ 'align': [] }],
            ['clean'],
            ['image', 'video']
          ],
          history: {
            delay: 1000,
            maxStack: 50,
            userOnly: false
          }
        },
        placeholder: '输入内容'
      },
      addImgRange: ''
    }
  },
  computed: {
    ...mapState('layout', ['isMobile', 'winWidth']),
    notValid () {
      const { content, title, date } = this.post
      return this.saving || !content || !title || !date
    },
    newReport: () => this.reportId.length === 0
  },
  mounted () {
    // 定义图片按钮的功能,使用上传服务器后返回的链接替换掉quill内置base64编码方式
    let imgHandler = async (image) => {
      this.addImgRange = this.$refs.newEditor.quill.getSelection()
      if (image) {
        this.$refs.uploader.triggerBrowseFiles()
      }
    }
    this.$refs.newEditor.quill.getModule('toolbar').addHandler('image', imgHandler)

    if (this.reportId === 'new') {
      this.newPost()
    } else {
      this.getPost(this.reportId)
    }
  },
  methods: {
    editCover (id) {
      if (!id) return
      this.changeCover = true
      this.$refs.uploader.triggerBrowseFiles()
    },
    savePost () {
      this.saving = true
      if (this.reportId === 'new') {
        this.$axios.post('/post/new', this.post).then(res => {
          this.saving = false
          this.$q.notify({
            type: 'positive',
            message: '保存成功'
          })
          this.$router.replace({name: 'cmsreports'})
        }).catch(err => {
          this.saving = false
          console.log(err)
          this.$q.notify('保存失败')
        })
      } else {
        this.$axios.put('/post/' + this.post._id, this.post).then(res => {
          this.$q.notify({
            type: 'positive',
            message: '保存成功'
          })
          this.save = false
          this.$router.replace({name: 'cmsreports'})
        }).catch(err => {
          this.save = false
          console.log(err)
          this.$q.notify('保存失败')
        })
      }
    },
    onEditorChange ({ quill, html, text }) {
      if (this.delayFlag) {
        this.delayFlag = false
        this.post.abstract = text.length > 70 ? text.substr(0, 70) : text
        setTimeout(() => {
          this.delayFlag = true
        }, this.changeDelay)
      }
    },
    filehandle (file, res, prog) {
      var value = res.src
      if (this.changeCover) {
        this.post.cover = value
        this.changeCover = false
      } else {
        let index = this.addImgRange != null ? this.addImgRange.index : 0 // 获取插入时的位置索引,如果获取失败,则插入到最前面
        this.$refs.newEditor.quill.insertEmbed(index, 'image', value, Quill.sources.USER)
        if (!this.post.cover) this.post.cover = value
        this.pictures.push(value)
      }
    },
    errhandle (file, res, prog) {
      this.changeCover = false
      this.$q.notify({
        type: 'warning',
        message: '上传失败'
      })
    },
    upgress (file, progress, sent) {
      this.progress = progress
    },
    getPost (id) {
      this.$axios.get('/post/' + id).then(res => {
        this.post = res.data
        this.uploadoptions.url = this.uplaodBase + this.post._id
      }).catch(err => {
        console.log(err)
      })
    },
    newPost () {
      this.$axios.get('/post/new').then(res => {
        this.post._id = res.data.id
        this.uploadoptions.url = this.uplaodBase + this.post._id
      }).catch(err => {
        console.log(err)
      })
    }
  }
}
</script>
.ql-editor .ql-video {
  width: 640px;
  height: 480px;
}
.ql-size-small {
  font-size: 0.8rem;
}
.ql-size-normal {
  font-size: 1rem;
}
.ql-size-large {
  font-size: 1.2rem;
}
.ql-size-huge {
  font-size: 1.5rem;
  font-weight: bold;
}

这样就ok了,简单的说就是分三步
1、修改video.js
2、vue中引入video.js
3、quill注册引入的video模块

使用和原来的一样,弹出url输入框时输入MP4文件的url地址就可以了

猜你喜欢

转载自blog.csdn.net/weixin_43587992/article/details/86296105