富文本编辑器quill-editor自定义图片上传

目录

1、页面引入

2、自定义imge处理的图片上传组件

3、图片上传成功后回显嵌入

4、最终呈现效果

5、源码


之前我整理过一篇文章,Quill编辑器实现图片上传功能(戳链接可查看)

但是想来那个是相当于自定义的更加简洁实用的工具栏toolbar,不过需要自定义的代码有些繁琐。

再遇到类似功能时我就想着寻找一个更简单的办法,使toolbar用原生的,仅仅改变img的处理方式。

注:上次quill是局部引用,这次是全局引用,不再赘述。两种方法各有优劣,各位看官,酌情使用。

1、页面引入

<!-- 富文本编辑器 -->
<el-form-item label="图文详情" prop="graphicDetails">                
    <quill-editor v-model="addForm.graphicDetails" ref="myQuillEditor"></quill-editor>
</el-form-item>

2、自定义imge处理的图片上传组件

思路:自定义的处理方法使之弹出自定义的图片上传组件即可,之后便是上传的那一套流程

    mounted() {
        this.$refs.myQuillEditor.quill
            .getModule('toolbar')
            .addHandler('image', this.imgHandler)
    },

        imgHandler(state) {
            this.addRange = this.$refs.myQuillEditor.quill.getSelection()
            if (state) {
                document.querySelector('.open-file').click()
            }
        },

        <el-upload action="" :show-file-list="false" :before-upload="quillUpload">
            <el-button v-show="false" ref="myButton" class="open-file" size="small" type="primary">点击上传</el-button>
        </el-upload>

3、图片上传成功后回显嵌入

        async quillUpload(file) {
            const isJPG = file.type === 'image/jpeg'
            const isLt2M = file.size / 1024 / 1024 < 5
            if (!isJPG) {
                this.$message.error('上传头像图片只能是 JPG 格式!')
                return
            }
            if (!isLt2M) {
                this.$message.error('上传头像图片大小不能超过 5MB!')
                return
            }
            var formData = new FormData()
            formData.append('file', file)
            const { data: res } = await this.$http.post('/upload', formData)
            if (!res.success) {
                //this.$message.error('图片上传失败!')
                return this.$message.error(res.msg)
            }
            var url = res.data.url
            var that = this
            setTimeout(function () {
                // 获取富文本组件实例
                let quill = that.$refs.myQuillEditor.quill
                // 获取光标所在位置
                let length = quill.getSelection().index
                quill.insertEmbed(length, 'image', url) // 调整光标到最后
                quill.setSelection(length + 1)
            }, 500)
        },

4、最终呈现效果

5、源码

之后再附上全部vue源码,方便各位参考。

<template>

    <!-- 卡片视图 -->
    <el-card>
        <!-- 提示 -->
        <el-alert title="添加商品信息" type="info" center show-icon :closable="false"></el-alert>

        <!-- Tab栏 -->
        <el-form :model="addForm" size="small" :rules="addFormRules" ref="addFormRef" label-width="100px">
            <el-form-item label="所属店铺" prop="shopId">
                <el-select v-model="addForm.shopId" placeholder="请选择" style="width:100%;">
                    <el-option v-for="item in shopList" :key="item.shopId" :label="item.shopName" :value="item.shopId">
                    </el-option>
                </el-select>
            </el-form-item>
            <el-form-item label="商品标题" prop="title">
                <el-input v-model="addForm.title"></el-input>
            </el-form-item>
            <el-form-item label="商品名称" prop="goodsName">
                <el-input v-model="addForm.goodsName"></el-input>
            </el-form-item>
            <el-form-item label="商品编号" prop="goodsNum">
                <el-input v-model="addForm.goodsNum"></el-input>
            </el-form-item>
            <el-form-item label="市场价格" prop="marketPrice">
                <el-input v-model="addForm.marketPrice" type="number"></el-input>
            </el-form-item>
            <el-form-item label="实际定价" prop="truePrice">
                <el-input v-model="addForm.truePrice" type="number"></el-input>
            </el-form-item>
            <el-form-item label="商品分类" prop="goodsType">
                <el-cascader v-model="addForm.goodsType" :show-all-levels="false" :options="treeList" :props="cascaderProps" @change="onCascadeChange" style="width:100%;"></el-cascader>
            </el-form-item>
            <el-form-item label="产地" prop="productionPlace">
                <el-input v-model="addForm.productionPlace"></el-input>
            </el-form-item>
            <el-form-item label="规格/重量" prop="spec">
                <el-input v-model="addForm.spec"></el-input>
            </el-form-item>
            <el-form-item label="数量" prop="stockNum">
                <el-input v-model="addForm.stockNum" type="number"></el-input>
            </el-form-item>
            <el-form-item label="保质期" prop="shelfLife">
                <el-input v-model="addForm.shelfLife"></el-input>
            </el-form-item>
            <!-- <el-form-item label="轮播图片" prop="">
                    <el-upload action="" list-type="picture-card" :on-remove="handleRemove" :http-request="UploadImage" :file-list="imgList">
                        <i class="el-icon-plus"></i>
                    </el-upload>
                </el-form-item> -->
            <el-form-item label="轮播图片" prop="">
                <el-image :src="item.url" style="width:178px;height:178px;" :key="index" v-for="(item,index) in imgList" :preview-src-list="[item.url]"></el-image>
                <el-upload v-if="imgList.length<5" accept="image/png, image/jpeg" class="avatar-uploader" action="" :show-file-list="false" :before-upload="beforeAvatarUpload">
                    <i class="el-icon-plus avatar-uploader-icon"></i>
                </el-upload>
            </el-form-item>
            <el-form-item label="商品主图" prop="mainImg">
                <el-radio-group v-model="addForm.mainImg">
                    <el-radio :label="item.url" :key="index" v-for="(item,index) in imgList" style="width: 178px;display:inline-block;text-align:center;margin-right:10px;">选择</el-radio>
                </el-radio-group>
            </el-form-item>

            <!-- 富文本编辑器 -->
            <el-form-item label="图文详情" prop="graphicDetails">
                <quill-editor v-model="addForm.graphicDetails" ref="myQuillEditor"></quill-editor>
            </el-form-item>
            <!-- 添加商品 -->
            <el-form-item>
                <el-button type="primary" @click="addGoods">添加</el-button>
                <el-button @click="cancelBtn">取消</el-button>
            </el-form-item>
        </el-form>
        <el-upload action="" :show-file-list="false" :before-upload="quillUpload">
            <el-button v-show="false" ref="myButton" class="open-file" size="small" type="primary">点击上传</el-button>
        </el-upload>

    </el-card>

</template>

<script>
import 'quill/dist/quill.snow.css'

export default {
    components: {},
    data() {
        return {
            shopList: [],
            imgList: [],
            addForm: {
                shopId: '',
                title: '',
                goodsName: '',
                goodsNum: '',
                productionPlace: '',
                shelfLife: '',
                truePrice: undefined,
                marketPrice: undefined,
                spec: '',
                stockNum: undefined,
                //轮播图
                carouselImg: '',
                //商品主图
                mainImg: '',
                goodsType: '',
                // 商品详情描述
                graphicDetails: '',
            },
            addFormRules: {
                title: [
                    {
                        required: true,
                        message: '请输入商品标题',
                        trigger: 'blur',
                    },
                ],
                goodsName: [
                    {
                        required: true,
                        message: '请输入商品名称',
                        trigger: 'blur',
                    },
                ],
                truePrice: [
                    {
                        required: true,
                        message: '请输入实际定价',
                        trigger: 'blur',
                    },
                ],
                marketPrice: [
                    {
                        required: true,
                        message: '请输入市场价格',
                        trigger: 'blur',
                    },
                ],
                promotionPrice: [
                    {
                        required: true,
                        message: '请输入促销价格',
                        trigger: 'blur',
                    },
                ],
                spec: [
                    {
                        required: true,
                        message: '请输入商品重量',
                        trigger: 'blur',
                    },
                ],
                stockNum: [
                    {
                        required: true,
                        message: '请输入商品数量',
                        trigger: 'blur',
                    },
                ],
                goodsType: [
                    {
                        required: true,
                        message: '请选择商品分类',
                        trigger: 'blur',
                    },
                ],
                mainImg: [
                    {
                        required: true,
                        message: '请选择商品主图',
                        trigger: 'change',
                    },
                ],
            },

            treeList: [],
            // 级联选择器配置
            cascaderProps: {
                // 配置触发选项 hover/click
                expandTrigger: 'hover',
                value: 'name',
                label: 'name',
                children: 'children',
                checkStrictly: true,
            },
            editorOption: {
                modules: {
                    toolbar: {
                        container: '#toolbar',
                        handlers: {
                            image: function (value) {
                                let that = this
                                if (value) {
                                    that.container
                                        .querySelector('.open-file')
                                        .click()
                                } else {
                                    this.quill.format('image', false)
                                }
                            },
                        },
                    },
                },
            },
        }
    },
    mounted() {
        this.getCascadeList()
        this.getShopList()
    },
    mounted() {
        this.$refs.myQuillEditor.quill
            .getModule('toolbar')
            .addHandler('image', this.imgHandler)
    },
    computed: {},
    methods: {
        // 点击图片ICON触发事件
        imgHandler(state) {
            this.addRange = this.$refs.myQuillEditor.quill.getSelection()
            if (state) {
                document.querySelector('.open-file').click()
            }
        },
        async quillUpload(file) {
            const isJPG = file.type === 'image/jpeg'
            const isLt2M = file.size / 1024 / 1024 < 5
            if (!isJPG) {
                this.$message.error('上传头像图片只能是 JPG 格式!')
                return
            }
            if (!isLt2M) {
                this.$message.error('上传头像图片大小不能超过 5MB!')
                return
            }
            var formData = new FormData()
            formData.append('file', file)
            const { data: res } = await this.$http.post('/upload', formData)
            if (!res.success) {
                //this.$message.error('图片上传失败!')
                return this.$message.error(res.msg)
            }
            var url = res.data.url
            var that = this
            setTimeout(function () {
                // 获取富文本组件实例
                let quill = that.$refs.myQuillEditor.quill
                // 获取光标所在位置
                let length = quill.getSelection().index
                quill.insertEmbed(length, 'image', url) // 调整光标到最后
                quill.setSelection(length + 1)
            }, 500)
        },
        async getShopList() {
            const { data: res } = await this.$http.get('/shop/singleList')

            if (!res.success) {
                //return this.$message.error('获取商品分类列表失败!')
                return this.$message.error(res.msg)
            }
            this.shopList = res.data
        },
        async beforeAvatarUpload(file) {
            const isJPG = file.type === 'image/jpeg'
            const isLt2M = file.size / 1024 / 1024 < 5

            if (!isJPG) {
                this.$message.error('上传头像图片只能是 JPG 格式!')
                return false
            }
            if (!isLt2M) {
                this.$message.error('上传头像图片大小不能超过 5MB!')
                return false
            }
            var formData = new FormData()
            formData.append('file', file)
            const { data: res } = await this.$http.post(
                '/uploadShrink',
                formData
            )
            console.info(res)
            if (!res.success) {
                //return this.$message.error('图片上传失败!')
                return this.$message.error(res.msg)
            }
            this.imgList.push({ url: res.data.url })
            console.info(this.imgList)
            return this.$message.success('图片上传成功!')
        },
        async getCascadeList() {
            const { data: res } = await this.$http.get('/category/treeList')

            if (!res.success) {
                //return this.$message.error('获取商品分类列表失败!')
                return this.$message.error(res.msg)
            }
            this.treeList = res.data
        },
        // 级联选择器选中项变化时出发
        // 把level id 加一并回传
        onCascadeChange(val) {
            this.addForm.goodsType = val[val.length - 1]
        },

        // 添加商品表单验证
        addGoods() {
            this.addForm.carouselImg = '' //初始化
            if (this.imgList.length == 0) {
                this.$message.error('请至少设置一张轮播图')
                return false
            } else {
                this.imgList.map((item) => {
                    this.addForm.carouselImg += item.url + ','
                })
                this.addForm.carouselImg = this.addForm.carouselImg.substring(
                    0,
                    this.addForm.carouselImg.length - 1
                )
            }
            this.$refs.addFormRef.validate(async (valid) => {
                if (!valid) return this.$message.error('表单验证不通过!')
                const { data: res } = await this.$http.post(
                    '/goods/add',
                    this.addForm
                )
                if (!res.success) return this.$message.error(res.msg)
                this.$message.success('添加商品成功!')
                this.$router.push('/goodsList')
            })
        },
        cancelBtn() {
            this.$router.push('/goodsList')
        },
    },
}
</script>

<style lang='less' scoped>
.el-checkbox {
    margin: 0 8px 0 0 !important;
}

.el-steps {
    margin-top: 15px;
    margin-bottom: 15px;
}
.el-tabs {
    margin-top: 15px;
}

// .avatar-uploader
.el-image {
    border: 1px dashed #d9d9d9;
    border-radius: 6px;
    width: 178px;
    height: 178px;
    margin-right: 10px;
}
.avatar-uploader {
    border: 1px dashed #d9d9d9;
    border-radius: 6px;
    height: 178px;
    cursor: pointer;
    display: inline-block;
    width: 178px;
    vertical-align: top;
}
.avatar-uploader:hover {
    border-color: #409eff;
}
.avatar-uploader-icon {
    font-size: 28px;
    color: #8c939d;
    width: 178px;
    height: 178px;
    //border: 1px solid red;
    //margin-top: 80px;
    line-height: 178px;
    text-align: center;
}
</style>

就是这样啦,如果你想让我知道你来过,欢迎关注、收藏和评论,本程序媛此刻心情好,过时不候^-^

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
Vue-Quill-Editor 是一个基于 Quill.js 的富文本编辑器,如果想要在编辑器中上传图片,可以自定义一个上传图片的方法。 首先,在 Vue-Quill-Editor 中定义一个上传图片的方法: ```javascript <template> <div ref="editor"> </div> </template> <script> import { quillEditor } from 'vue-quill-editor' export default { components: { quillEditor }, methods: { uploadImage(file) { const formData = new FormData() formData.append('file', file) // 发送请求上传文件 // 返回图片地址 return Promise.resolve('https://your-cdn.com/' + file.name) } } } </script> ``` 然后在 `quill-editor` 组件上设置 `:custom-options` 属性,将上传图片的方法传递给 Quill.js: ```javascript <quill-editor ref="myQuillEditor" :custom-options="{ modules: { toolbar: [ ['bold', 'italic', 'underline', 'strike'], [{ header: [1, 2, false] }], ['blockquote', 'code-block'], [{ 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'], ['link', 'image', 'video'] ], imageDrop: true, imageResize: {}, imageExtend: { loading: true, headers: { 'Authorization': 'Bearer ' + token }, url: 'https://your-api.com/upload/image', method: 'POST', size: 2 * 1024 * 1024, compress: true, convertSize: 1080, format: 'image/jpeg', altKey: true, responseFn: response => { // 返回图片地址 return 'https://your-cdn.com/' + response.data.url } } }, placeholder: '请输入内容', theme: 'snow' }" @ready="onEditorReady" ></quill-editor> ``` 这里主要是设置 `imageExtend` 属性,其中 `url` 属性为上传图片的接口地址, `responseFn` 为上传图片成功后返回的数据处理方法。 最后在 `uploadImage` 方法中发送请求上传图片,并返回图片地址即可。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

菜鸟茜

随多随少随你心意^-^

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值