vue-quill-editor富文本编辑器实现多图片上传到服务器

3,430 阅读1分钟

vue-quill-editor是一个简单实用的富文本编辑器(官网),内置提供quill-image-extend-module模块(地址)支持图片上传图片到服务器而不是生成base64,但是有个明显的缺陷是只能上传一张(即使不用这个插件也只能上传一张生成base64 =。=), 这是个明显缺陷,而且操作后台的运营肯定不干(我™辛辛苦苦整理好的商品详情图片列表你让我一个个上传?),所以还是要多图片上传还是要实现,请看下面代码:

基于vue-quill-editor 再做一次封装:

<template>
    <div class="quill-editor-container">
        <quill-editor
            v-if="showEditor"
            v-model="content"
            :options="editorOption"
            @change="onEditorChange($event)">
        </quill-editor>
    </div>
</template>


<script>
    import 'quill/dist/quill.core.css'
    import 'quill/dist/quill.snow.css'
    import 'quill/dist/quill.bubble.css'
    import { quillEditor, Quill } from 'vue-quill-editor'
    import { getUploadSign } from "@/api/goods"
    // 配置参照这里
    // https://github.com/surmon-china/vue-quill-editor/blob/master/src/editor.vue
    import toolbar from './toolbar'
    
    const Delta = Quill.import('delta')
    export default {
        name: 'QuillEditor',
        components: {
            quillEditor
        },
        props: {
            value: {
                type: String, 
                default: '',
            }
        },
        data () {
            return {
                showEditor: false,
                imgSign: {},
                content: this.value || '',
                editorOption: {}
            }
        },
        watch: {
            value(val) {
                this.content = val
            },
        },
        mounted () {    
            this.getImgSign()  
        },  
        methods: {  
            // 获取图片上传签名(因为上传到腾讯云,所以要一些额外参数)
            getImgSign() {      
                getUploadSign().then(({ data }) => {        
                    this.imgSign = data       
                    this.setEditorOption()     
                })    
            },    
            // 设置配置信息
            setEditorOption() {
                // 当前组件实例      
                let vm = this      
                this.editorOption = Object.assign(this.editorOption, {        
                    placeholder: '请插入内容...',       
                    modules: {          
                        toolbar: {            
                            container: toolbar,           
                             handlers: {              
                                // 自定义上传图片到服务器             
                                image: function() { 
                                    // quill插件实例               
                                    let _self = this  
                                    // 创建上传文件input并触发
                                    let fileInput = document.createElement('input')                
                                    fileInput.setAttribute('type', 'file')                
                                    fileInput.setAttribute('multiple', 'multiple')                
                                    fileInput.setAttribute('accept', 'image/*')                
                                    fileInput.addEventListener('change', () => {                  
                                        if (fileInput.files !== null) {                    
                                            const files = Array.from(fileInput.files).reverse()                    
                                            // 利用es6迭代器异步顺序上传图片,保证图片插入顺序正常                  
                                            const it = files[Symbol.iterator]()                    
                                            uploadFile()   
                 
                                            function uploadFile () {                      
                                               const { done, value: _file } = it.next()                      
                                                if (done) return                      
                                                let reader = new FileReader()                      
                                                reader.onload = (event) => {                        
                                                    const range = _self.quill.getSelection(true)  
                                                    // 设置图片上传地址
                                                    const uploadImgServer = 'https://upload.chujiayoupin.com/v1/upload/file'                        
                                                    // 创建formData参数提交(文件+签名信息)                  
                                                    const formData = new FormData()                        
                                                    formData.append('file', _file)                        
                                                    for (const [key, val] of Object.entries(vm.imgSign)) {                          
                                                        formData.append(key, val)                        
                                                    }                        
                                                    // 发送图片上传请求                     
                                                    const xhr = new XMLHttpRequest()                        
                                                    xhr.open('POST', uploadImgServer)                        
                                                    xhr.timeout = 6000                        
                                                    xhr.ontimeout = () => {                          
                                                        alert('图片上传超时')                        
                                                    }                        
                                                    xhr.onreadystatechange = () => {                          
                                                        let result                          
                                                        if (xhr.readyState === 4) {                                            
                                                            // http status code                            
                                                            if (xhr.status < 200 || xhr.status >= 300) {   
                                                                return alert(`上传图片发生错误,上传图片发生错误,服务器返回状态是 ${xhr.status}`)                            
                                                            }                            
                                                            result = xhr.responseText                            
                                                            if (typeof result !== 'object') {                              
                                                                try {                                
                                                                    result = JSON.parse(result)                              
                                                                } catch {                                
                                                                    return alert('上传图片失败', '上传图片返回结果错误,返回结果是: ' + result)                              
                                                                }                            
                                                            } 
                                                            // 根据服务器返回的结果自行拼接图片地址
                                                            const URI = result.data.items.file.map(v => `https://img.chujiayoupin.com${v.filename}`)[0]                            
                                                            // 插入到文本                            
                                                            _self.quill.updateContents(                              
                                                                new Delta()                                
                                                                    .retain(range.index)                                
                                                                    .delete(range.length)                                
                                                                    .insert({ image: URI })                            
                                                            )                          
                                                        }                          
                                                        // 上传下一个图片                         
                                                        uploadFile()                        
                                                    }                        
                                                    xhr.send(formData)                      
                                                }                      
                                                reader.readAsDataURL(_file)                    
                                            }       
                                        }                
                                    })                
                                    fileInput.click()              
                                }            
                            }         
                        }        
                    }      
                })      
                this.$nextTick(() => {        
                    this.showEditor = true      
                })    
            },    
            // 文本改变后同步回父组件绑定的值   
            onEditorChange(event) {      
                this.$emit('input', event.html)    
            }  
        }
    }
</script>



// 设定编辑器高度
<style lang="less" scoped>  
    .quill-editor /deep/ .ql-container {    
        height: 360px;  
    }
</style>

父组件引入

<QuillEditor v-model="xxx" />

这样就OK啦(*^__^*) ……