Vue-VEditor(富文本)

组件代码:

<!-- 富文本组件,使用说明见README.md-->
<template>
    <div class='YxkEditor'>
        <!-- 富文本 -->
        <template>
            <div :class="[{'YxkEditor__noToolbar': params.hideToolbar}]">
                <quill-editor v-bind="editorBind(editorObj)" @change="change($event)" @focus="focus($event)"
                    @blur="blur($event)">
                </quill-editor>
            </div>
        </template>
        <!-- 富文本字数统计 -->
        <template>
            <div v-if="params.size" class="YxkEditor__size">{{params.length}}/{{params.size}}</div>
        </template>
        <!-- 富文本图片/视频上传 -->
        <template>
            <YxkUpload v-if="!params.disabledUpload" :uploadObj="uploadBind(uploadObj)" ref="YxkEditor_upload"
                @change="changeUrl"></YxkUpload>
        </template>
    </div>
</template>

<script>
    import {
        quillEditor
    } from "vue-quill-editor"
    import "quill/dist/quill.snow.css"

    export default {
        name: 'YxkEditor',
        props: {
            editorObj: {
                type: Object
            },
            uploadObj: {
                type: Object
            }
        },
        components: {
            quillEditor
        },
        data() {
            return {
                params: { // 参数
                    times: 0, // 防止字数统计错误
                    length: 0, // 富文本输入字数
                    size: 0, // 字数限制
                    readOnly: '', // 只读
                    hideToolbar: '', // 隐藏工具栏
                    disabledUpload: '', // 禁止上传
                },
                defaultToolbar: [], // 默认工具栏   
            }
        },
        methods: {
            // 富文本事件
            change(e) { // change
                // 字数限制
                this.sizeSet(e)
                this.$emit("change", {
                    ...e,
                    length: e.quill.getLength() - 1
                })
            },
            focus(e) { // 获取焦点
                this.$emit('focus', {
                    ...e
                })
            },
            blur(e) { // 失去焦点 
                this.$emit('blur', {
                    ...e
                })
            },
            // 上传图片、视频
            uploadBind(obj) {
                return Object.assign({
                    size: 60,
                    clearFiles: true,
                    accept: '.png,.jpg,.gif,.mp4'
                }, obj)
            },
            changeUrl(obj) {
                obj.uploadUrl.forEach((item, index) => {
                    let video = obj.fileList[index].name.indexOf('.mp4') != -1
                    this.imageSet(item.url, video)
                })
            },
            editorUpload() {
                if (this.params.readOnly || this.params.disabledUpload) return false
                document.querySelector(".YxkEditor .el-icon-plus").click()
            },
            // 插入视频、图片
            imageSet(url, video) {
                let quill = this.$refs.YxkEditor.quill;
                let length = quill.getSelection().index;
                quill.insertEmbed(length, `${video ? 'video' : 'image'}`, url)
                quill.setSelection(length + 1)
            },
            // 字数限制
            sizeSet(e) {
                this.params.length = e.quill.getLength() - 1
                if (this.params.size) {
                    if (this.params.length > this.params.size) {
                        e.quill.deleteText(this.params.size, 100000)
                    }
                }
            },
            // 参数设置
            paramsSet(obj) {
                this.params.size = obj.size ? Number(obj.size) : 0
                this.params.readOnly = obj.readOnly
                this.params.hideToolbar = obj.hideToolbar
                this.params.disabledUpload = obj.disabledUpload
                // 字数统计
                if (!this.params.times) {
                    if (obj.size && obj.content !== undefined) {
                        this.params.length = obj.content.length
                    }
                    this.params.times += 1
                }
                // 是否只读
                if (this.$refs[obj.ref]) {
                    if (obj.readOnly) {
                        this.$refs[obj.ref].quill.enable(false)
                    } else {
                        this.$refs[obj.ref].quill.enable(true)
                    }
                    this.sizeSet(this.$refs[obj.ref])
                }
            },
            // 富文本设置
            editorSet(obj) {
                let quillRef = this.$refs[obj.ref]
                if (quillRef) {
                    quillRef.quill.clipboard.addMatcher("IMG", // 剪切板删除img
                        function () {
                            return {
                                ops: []
                            };
                        }
                    )
                }
            },
            // 配置项
            editorBind(params) {
                let obj = JSON.parse(JSON.stringify(params)) || {}
                let dataBind = {
                    ref: 'YxkEditor',
                    options: { // 富文本配置项
                        theme: 'snow',
                        placeholder: '请输入...',
                        modules: {
                            toolbar: {
                                container: this.defaultToolbar,
                                handlers: {
                                    image: (val) => {
                                        if (val) {
                                            this.editorUpload()
                                        } else {
                                            this.quill.format("image", false)
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
                if (obj.options) {
                    dataBind.options = Object.assign({}, obj.options, dataBind.options)
                }
                if (obj.modules) {
                    if (obj.modules.toolbar) {
                        Object.assign(dataBind.modules.toolbar, obj.modules.toolbar)
                    }
                    Object.assign(dataBind.modules, obj.modules)
                    delete obj.modules
                }
                Object.assign(dataBind, obj)
                this.paramsSet(dataBind)
                this.editorSet(dataBind)
                return dataBind
            },
            // 初始化
            initialSet() {
                this.defaultToolbar = [ // 工具栏
                    ['bold', 'italic', 'underline', 'strike'], //加粗,斜体,下划线,删除线
                    ['blockquote'], //引用,代码块
                    [{
                        'list': 'ordered'
                    }, {
                        'list': 'bullet'
                    }], //列表
                    [{
                        'indent': '-1'
                    }, {
                        'indent': '+1'
                    }], // 缩进
                    [{
                        'size': ['small', false, 'large']
                    }], // 字体大小
                    [{
                        'color': ['#FFFFFF', '#333333', '#666666', '#999999']
                    }], // 字体颜色,字体背景颜色
                    [{
                        'align': []
                    }], //对齐方式
                    ['clean'], //清除字体样式
                    ['image', 'link'] //上传图片、上传视频
                ]
            }
        },
        computed: {},
        watch: {},
        created() {
            this.initialSet()
        },
        mounted() {}
    }
</script>

<style lang='scss'>
    .YxkEditor {
        position: relative;

        .YxkUpload {
            width: 0;
            height: 0;
            overflow: hidden;
            opacity: 0 !important;
        }

        .YxkEditor__size {
            position: absolute;
            right: 15px;
            bottom: 5px;
            color: #999;
        }

        .YxkEditor__noToolbar {
            .ql-toolbar {
                display: none;
            }
        }

        .ql-picker.ql-size {

            .ql-picker-label::before,
            .ql-picker-item::before {
                content: "14px";
            }

            .ql-picker-label[data-value="small"]::before,
            .ql-picker-item[data-value="small"]::before {
                content: "12px";
            }

            .ql-picker-label[data-value="large"]::before,
            .ql-picker-item[data-value="large"]::before {
                content: "16px";
            }
        }

        .quill-editor {
            .ql-container {
                height: 300px;
                border-top: #ccc solid 1px !important;
            }

            .ql-toolbar {
                border-bottom: none;

                button,
                .ql-size,
                .ql-color,
                .ql-align {
                    position: relative;

                    &::after {
                        content: '';
                        position: absolute;
                        bottom: -20px;
                        left: 10%;
                        display: none;
                        width: 80px;
                        color: #000;
                        font-size: 12px;
                        line-height: 12px;
                        padding: 3px 2px;
                        text-align: center;
                        border: #999 solid 1px;
                        background: #fff;
                        transform: translateX(-50%);
                    }

                    &:hover {
                        &::after {
                            display: block;
                        }
                    }
                }

                .ql-bold {
                    &::after {
                        content: '加粗';
                    }
                }

                .ql-italic {
                    &::after {
                        content: '斜体';
                    }
                }

                .ql-underline {
                    &::after {
                        content: '下划线';
                    }
                }

                .ql-strike {
                    &::after {
                        content: '删除线';
                    }
                }

                .ql-blockquote {
                    &::after {
                        content: '引用';
                    }
                }

                .ql-list {
                    &:first-child {
                        &::after {
                            content: '有序列表';
                        }
                    }

                    &:last-child {
                        &::after {
                            content: '无序列表';
                        }
                    }
                }

                .ql-indent {
                    &:first-child {
                        &::after {
                            content: '向左缩进';
                        }
                    }

                    &:last-child {
                        &::after {
                            content: '向右缩进';
                        }
                    }
                }

                .ql-picker {
                    .ql-picker-label {
                        display: flex;
                    }
                }

                .ql-size {
                    width: 60px;

                    &::after {
                        content: '字体大小';
                    }
                }

                .ql-color {
                    &::after {
                        content: '字体颜色';
                    }
                }

                .ql-align {
                    &::after {
                        content: '对齐方式';
                    }
                }

                .ql-clean {
                    &::after {
                        content: '清除样式';
                    }
                }

                .ql-image {
                    &::after {
                        content: '图片/视频';
                    }
                }

                .ql-link {
                    &::after {
                        content: '添加链接';
                    }
                }
            }
        }

        .quill-editor {
            box-shadow: none;
        }
    }
</style>

示例:

 

 

参数说明:

 

 

 

posted @ 2022-09-22 18:43  忙着可爱呀~  阅读(500)  评论(0)    收藏  举报