富文本编辑器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> |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· 写一个简单的SQL生成工具
· Manus的开源复刻OpenManus初探