富文本编辑器Quill(二)上传图片与视频

image与video在Quill formats中属于Embeds,要在富文本中插入图片或者视频需要使用insertEmbed api。

insertEmbed

1
insertEmbed(index: Number, type: String, value: any, source: String = 'api'): Delta

插入图片需要位置,内容类型以及图片的url:

1
quill.insertEmbed(10, 'image', 'https://quilljs.com/images/cloud.png')

获取位置:

1
const range = quill.getSelection();

上传图片

首先toolbar中添加image,还需要一个隐藏input元素用来上传图片:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<template>
  <div>
    <div id="toolbar">
      <span class="ql-formats">
        <button class="ql-image"></button>
        <button class="ql-video"></button>
      </span>
    </div>
    <div id="editor">
      <p>Hello World!</p>
      <p>Some initial <strong>bold</strong> text</p>
      <p><br></p>
    </div>
    <input id="uploadImg" type="file" style="display:none" accept="image/png, image/jpeg, image/gif" @change="uploadImage">
  </div>
</template>

为image添加handler,点击时上传图片:

1
this.quill.getModule("toolbar").addHandler("image", this.uploadImageHandler)

handler:

1
2
3
4
5
uploadImageHandler () {
  const input = document.querySelector('#uploadImg')
  input.value = ''
  input.click()
},

为input元素添加onchange事件,获取上传图片,上传服务器,获取图片地址,将地址插入到编辑器中:

1
2
3
4
5
6
7
8
9
async uploadImage (event) {
    const form = new FormData()
    form.append('upload_file', event.target.files[0])
    const url = await $.ajax(...)  #上传图片 获取地址
    const addImageRange = this.quill.getSelection()
    const newRange = 0 + (addImageRange !== null ? addImageRange.index : 0)
    this.quill.insertEmbed(newRange, 'image', url)
    this.quill.setSelection(1 + newRange)
  }

  全部代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
<template>
  <div>
    <div id="toolbar">
      <span class="ql-formats">
        <button class="ql-image"></button>
        <button class="ql-video"></button>
      </span>
    </div>
    <div id="editor">
      <p>Hello World!</p>
      <p>Some initial <strong>bold</strong> text</p>
      <p><br></p>
    </div>
    <input id="uploadImg" type="file" style="display:none" accept="image/png, image/jpeg, image/gif" @change="uploadImage">
  </div>
</template>
 
<script>
import Quill from 'quill'
 
export default {
  name: "QuillEditor",
  mounted () {
    this.initQuill()
  },
  beforeDestroy () {
    this.quill = null
    delete this.quill
  },
  methods: {
    initQuill () {
      const quill = new Quill('#editor', {
        theme: 'snow',
        modules: {
          toolbar: '#toolbar'
        }
      })
      this.quill = quill
      this.quill.getModule("toolbar").addHandler("image", this.uploadImageHandler)
    },
    uploadImageHandler () {
      const input = document.querySelector('#uploadImg')
      input.value = ''
      input.click()
    },
    async uploadImage (event) {
      const form = new FormData()
      form.append('upload_file', event.target.files[0])
      const url = await $.ajax(...)
      const addImageRange = this.quill.getSelection()
      const newRange = 0 + (addImageRange !== null ? addImageRange.index : 0)
      this.quill.insertEmbed(newRange, 'image', url)
      this.quill.setSelection(1 + newRange)
    }
  }
}
</script>

上传视频做些少许修改就可以了:

1
<input id="uploadVideo" type="file" style="display:none" accept="video/*" @change="uploadVideo">
1
this.quill.getModule("toolbar").addHandler("video", this.uploadVideoHandler)
1
uploadVideoHandler () {...}
1
async uploadVideo (event) {...}

定制Video

默认的video上传会存在一个问题,上传后video是放在iframe中的,一般情况下是没有问题的,但在小程序中使用h5页面时,iframe中的域名需要添加到小程序业务域名中,否则会禁止访问。

更好的解决方法是简单的添加一个video元素,而不是iframe,我们需要定制一个Video Embed。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
const BlockEmbed = Quill.import('blots/block/embed')
class VideoBlot extends BlockEmbed {
  static create (value) {
    let node = super.create()
    node.setAttribute('src', value.url)
    node.setAttribute('controls', value.controls)
    node.setAttribute('width', value.width)
    node.setAttribute('height', value.height)
    node.setAttribute('webkit-playsinline', true)
    node.setAttribute('playsinline', true)
    node.setAttribute('x5-playsinline', true)
    return node;
  }
 
  static value (node) {
    return {
      url: node.getAttribute('src'),
      controls: node.getAttribute('controls'),
      width: node.getAttribute('width'),
      height: node.getAttribute('height')
    };
  }
}

注册:

1
2
3
VideoBlot.blotName = 'simpleVideo'
VideoBlot.tagName = 'video'
Quill.register(VideoBlot)

插入Embed:

1
2
3
4
5
6
this.quill.insertEmbed(newRange, 'simpleVideo', {
  url,
  controls: 'controls',
  width: '100%',
  height: '100%'
})

添加效果:

1
<video src="...mp4" controls="controls" width="100%" height="100%" webkit-playsinline="true" playsinline="true" x5-playsinline="true"></video>

  

posted @   再见紫罗兰  阅读(17724)  评论(0编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· 写一个简单的SQL生成工具
· Manus的开源复刻OpenManus初探
点击右上角即可分享
微信分享提示