基于 Vue2+Quill 的富文本编辑器全方案:功能实现与样式优化

在 Web 开发中,富文本编辑器是内容管理系统、博客平台等应用的核心组件。本文将详细介绍如何基于 Vue 和 Quill
构建一个功能完善、样式精美的富文本编辑器,重点解决字体字号选项冗长、样式不美观及功能完整性问题,提供可直接部署使用的完整方案。

一、方案概述

本方案基于 Vue 2.x 和 Quill 编辑器,实现了以下核心功能:

  • 完整的字体体系(中文字体 + 英文字体)
  • 丰富的字号选择(8px-64px)
  • 优化的 UI 设计,解决原生 Quill 样式简陋问题
  • 图片 / 视频上传功能
  • Markdown 快捷操作支持
  • 响应式布局适配

为什么选择 Quill?相比其他编辑器(如 TinyMCE、CKEditor),Quill 具有轻量、可扩展性强、API 友好等特点,非常适合需要自定义功能的场景。

二、环境准备与依赖安装

2.1 基础环境

  • Node.js (v14+)
  • Vue CLI (可选,用于快速创建项目)
  • Vue 2.x (当前 vue-quill-editor 对 Vue 3 支持有限)

2.2 依赖安装

# 安装核心编辑器
npm install vue-quill-editor --save

# 安装Quill本体
npm install quill --save

# 安装Markdown快捷键插件
npm install quill-markdown-shortcuts --save

# 安装图片上传扩展模块
npm install quill-image-super-solution-module --save

三、组件封装

<template>
    <div class="quill-editor-container">
        <!-- 富文本编辑器主体 -->
        <quill-editor v-model="content" ref="myQuillEditor" :options="editorOption" class="editor"
            @input="handleContentChange"></quill-editor>

        <!-- 视频上传隐藏输入框 -->
        <input type="file" id="video-upload-input" accept="video/*" style="display: none" @change="handleVideoUpload" />
    </div>
</template>

<script>
// 引入Quill编辑器样式
import 'quill/dist/quill.core.css'
import 'quill/dist/quill.snow.css'
import 'quill/dist/quill.bubble.css'

// 引入Vue-Quill编辑器组件和Quill核心库
import { quillEditor, Quill } from 'vue-quill-editor'

// 引入Markdown快捷操作插件
import MarkdownShortcuts from 'quill-markdown-shortcuts'

// 引入图片上传扩展模块
import { container, ImageExtend, QuillWatch } from "quill-image-super-solution-module"

// 引入HTTP请求工具
import request from "@/utils/request"

// 引入图片处理混入
import imageMixin from "@/mixins/imageMixin"

// 注册Markdown快捷键模块
Quill.register('modules/markdownShortcuts', MarkdownShortcuts)

// 注册图片扩展模块
Quill.register('modules/ImageExtend', ImageExtend)

// 字体配置
const fonts = [
    'SimSun', 'SimHei', 'Microsoft-YaHei', 'KaiTi', 'FangSong',
    'YouYuan', 'LiSu', 'STSong', 'STZhongsong', 'STKaiti',
    'STFangsong', 'Arial', 'Times-New-Roman', 'Courier-New', 'Verdana',
    'Georgia', 'Impact', 'Comic-Sans-MS', 'sans-serif', 'serif', 'monospace'
]
const Font = Quill.import('formats/font')
Font.whitelist = fonts
Font.format = function (node, value) {
    if (value) {
        fonts.forEach(font => node.classList.remove(`ql-font-${font}`));
        node.classList.add(`ql-font-${value}`);
    } else {
        fonts.forEach(font => node.classList.remove(`ql-font-${font}`));
    }
};
Quill.register(Font, true)

// 字号配置
const sizes = [
    '8px', '10px', '12px', '14px', '16px', '18px',
    '20px', '22px', '24px', '26px', '28px',
    '30px', '32px', '36px', '40px', '48px', '56px', '64px'
]
const Size = Quill.import('formats/size')
Size.whitelist = sizes
Quill.register(Size, true)

// 自定义视频Blot
const VideoBlot = Quill.import('formats/video')
const ATTRIBUTES = ['height', 'width', 'controls']

if (!Quill.imports['formats/custom-video']) {
    class CustomVideoBlot extends VideoBlot {
        static formats(domNode) {
            return ATTRIBUTES.reduce((formats, attribute) => {
                if (domNode.hasAttribute(attribute)) {
                    formats[attribute] = domNode.getAttribute(attribute)
                }
                return formats
            }, {})
        }

        format(name, value) {
            if (ATTRIBUTES.includes(name)) {
                if (value) {
                    this.domNode.setAttribute(name, value)
                } else {
                    this.domNode.removeAttribute(name)
                }
            } else {
                super.format(name, value)
            }
        }
    }
    CustomVideoBlot.blotName = 'custom-video'
    CustomVideoBlot.tagName = 'VIDEO'
    Quill.register(CustomVideoBlot)
}

export default {
    name: 'RichTextEditor', // 组件名称,用于注册和引用
    mixins: [imageMixin],
    components: { quillEditor },
    props: {
        // 接收外部传入的内容,实现双向绑定
        value: {
            type: String,
            default: ''
        },
        // 编辑器高度
        height: {
            type: Number,
            default: 500
        },
        // 图片上传接口地址
        imageUploadUrl: {
            type: String,
            default: '/api/v1/cos/batch/upload/article'
        },
        // 视频上传接口地址
        videoUploadUrl: {
            type: String,
            default: '/cos/batch/upload/video'
        },
        // 最大图片大小(MB)
        maxImageSize: {
            type: Number,
            default: 2
        },
        // 最大视频大小(MB)
        maxVideoSize: {
            type: Number,
            default: 50
        }
    },
    data() {
        return {
            content: this.value, // 内部维护的内容状态
            uploadedImages: [], // 已上传图片列表
            uploadedVideos: [], // 已上传视频列表
            editorOption: {
                theme: 'snow',
                modules: {
                    markdownShortcuts: {},
                    ImageExtend: {
                        loading: true,
                        name: 'files',
                        size: this.maxImageSize,
                        action: this.imageUploadUrl,
                        accept: 'image/jpg, image/png, image/gif, image/jpeg, image/bmp, image/x-icon',
                        response: (res) => {
                            const imageUrl = res.data[0]
                            this.uploadedImages.push(imageUrl)
                            // 触发图片上传成功事件
                            this.$emit('image-uploaded', imageUrl)
                            return this.getImageUrl(imageUrl)
                        },
                        headers: (xhr) => {
                            const token = localStorage.getItem('token') || ''
                            if (token) {
                                xhr.setRequestHeader('Authorization', `Bearer ${token}`)
                            }
                        },
                        sizeError: () => {
                            this.$message.error(`图片大小不能超过 ${this.maxImageSize}MB!`)
                        },
                        error: (err) => {
                            this.$message.error('图片上传失败,请重试')
                            this.$emit('upload-error', { type: 'image', error: err })
                            console.error('图片上传错误:', err)
                        },
                        change: (xhr, formData) => {
                            formData.append('type', 'article')
                        }
                    },
                    toolbar: {
                        container: [
                            [{ 'font': fonts }],
                            [{ 'size': sizes }],
                            ['bold', 'italic', 'underline', 'strike'],
                            [{ 'color': [] }, { 'background': [] }],
                            [{ 'script': 'sub' }, { 'script': 'super' }],
                            [{ 'header': 1 }, { 'header': 2 }],
                            [{ 'list': 'ordered' }, { 'list': 'bullet' }],
                            [{ 'indent': '-1' }, { 'indent': '+1' }],
                            [{ 'align': [] }],
                            ['link', 'image', 'video'],
                            ['blockquote', 'code-block'],
                            ['clean']
                        ],
                        handlers: {
                            'image': function () {
                                QuillWatch.emit(this.quill.id)
                            },
                            'video': function () {
                                document.getElementById('video-upload-input').click()
                            }
                        }
                    }
                }
            }
        }
    },
    watch: {
        // 监听外部传入的value变化,同步到组件内部
        value(newVal) {
            if (newVal !== this.content) {
                this.content = newVal
            }
        },
        // 监听高度变化,更新编辑器样式
        height(newVal) {
            this.$nextTick(() => {
                const editorEl = this.$el.querySelector('.editor')
                if (editorEl) {
                    editorEl.style.minHeight = `${newVal}px`
                }
            })
        }
    },
    methods: {
        // 内容变化时触发,向父组件传递最新内容
        handleContentChange() {
            this.$emit('input', this.content)
            this.$emit('change', this.content)
        },

        // 处理视频上传
        async handleVideoUpload(e) {
            const file = e.target.files[0]
            if (!file) return

            // 验证视频文件
            if (!this.validateVideoFile(file)) {
                e.target.value = ''
                return
            }

            // 显示加载中
            const loading = this.$loading({
                lock: true,
                text: '视频上传中,请稍候...',
                spinner: 'el-icon-loading',
                background: 'rgba(0, 0, 0, 0.7)'
            })

            try {
                const formData = new FormData()
                formData.append('files', file)

                // 上传视频
                const res = await request({
                    url: this.videoUploadUrl,
                    method: 'post',
                    data: formData,
                    headers: { 'Content-Type': 'multipart/form-data' }
                })

                if (!res || !res.data || res.data.length === 0) {
                    throw new Error('视频上传失败,返回格式不正确')
                }

                // 处理上传结果
                const videoUrl = res.data[0]
                this.uploadedVideos.push(videoUrl)
                this.$emit('video-uploaded', videoUrl)

                // 将视频插入编辑器
                const quill = this.$refs.myQuillEditor.quill
                const range = quill.getSelection()
                const insertIndex = range ? range.index : quill.getLength() - 1
                quill.insertEmbed(insertIndex, 'custom-video', this.getImageUrl(videoUrl))

                // 设置视频属性
                this.$nextTick(() => {
                    const lastIndex = quill.getLength() - 1
                    const [videoBlot] = quill.getLine(lastIndex)
                    if (videoBlot && videoBlot.statics.blotName === 'custom-video') {
                        videoBlot.format('controls', 'controls')
                        videoBlot.format('width', '100%')
                        videoBlot.format('height', 'auto')
                    }
                    quill.setSelection(lastIndex + 1)
                })

                this.$message.success('视频上传成功')
            } catch (error) {
                console.error('视频上传错误详情:', error)
                this.$message.error(`视频上传失败: ${error.message || '未知错误'}`)
                this.$emit('upload-error', { type: 'video', error: error })
            } finally {
                loading.close()
                e.target.value = '' // 重置输入框,允许重复上传同一文件
            }
        },

        // 验证视频文件格式和大小
        validateVideoFile(file) {
            const videoTypes = ['video/mp4', 'video/ogg', 'video/webm', 'video/avi', 'video/mov']
            if (!videoTypes.includes(file.type)) {
                this.$message.error('请上传支持的视频格式(MP4、OGG、WEBM、AVI、MOV)')
                return false
            }

            const maxSizeBytes = this.maxVideoSize * 1024 * 1024
            if (file.size > maxSizeBytes) {
                this.$message.error(`视频大小不能超过 ${this.maxVideoSize}MB`)
                return false
            }

            return true
        },

        // 获取编辑器实例
        getEditorInstance() {
            return this.$refs.myQuillEditor.quill
        },

        // 清空编辑器内容
        clearContent() {
            this.content = ''
            this.$emit('input', '')
        },

        // 获取已上传的媒体文件列表
        getUploadedFiles() {
            return {
                images: [...this.uploadedImages],
                videos: [...this.uploadedVideos]
            }
        }
    }
}
</script>

<style scoped>
.quill-editor-container {
    width: 100%;
    box-sizing: border-box;
}

.editor {
    min-height: 500px;
}

::v-deep .ql-container {
    min-height: 400px !important;
    border: 1px solid #e5e7eb !important;
    border-radius: 0 0 6px 6px;
}

::v-deep .ql-toolbar {
    border: 1px solid #e5e7eb !important;
    border-bottom: none !important;
    border-radius: 6px 6px 0 0;
    background-color: #f9fafb;
}

::v-deep .ql-editor img,
::v-deep .ql-editor video {
    max-width: 100%;
    height: auto;
    margin: 10px 0;
}

::v-deep .ql-editor video {
    min-height: 300px;
    border: 1px solid #eee;
}
</style>

<style>
.ql-snow .ql-picker.ql-font {
    width: 140px;
    margin-right: 8px;
    height: 30px;
    display: flex;
    align-items: center;
}



/* 字号选择器样式优化 */
.ql-snow .ql-picker.ql-size {
    width: 80px;
    margin-right: 8px;
    height: 30px;
    display: flex;
    align-items: center;
}

/* 下拉菜单容器优化 - 解决选项过多问题 */
.ql-snow .ql-picker.ql-font .ql-picker-options {
    max-height: 280px;
    overflow-y: auto;
    border-radius: 6px;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
    border: 1px solid #e2e8f0;
    padding: 4px 0;
    width: 140px;
}

.ql-snow .ql-picker.ql-size .ql-picker-options {
    max-height: 280px;
    overflow-y: auto;
    border-radius: 6px;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
    border: 1px solid #e2e8f0;
    padding: 4px 0;
    width: 80px;
}

/* 滚动条美化 */
.ql-snow .ql-picker-options::-webkit-scrollbar {
    width: 6px;
}

.ql-snow .ql-picker-options::-webkit-scrollbar-track {
    background: #f1f5f9;
    border-radius: 3px;
}

.ql-snow .ql-picker-options::-webkit-scrollbar-thumb {
    background: #cbd5e1;
    border-radius: 3px;
}

.ql-snow .ql-picker-options::-webkit-scrollbar-thumb:hover {
    background: #94a3b8;
}

/* 下拉菜单项样式优化 */
.ql-snow .ql-picker-item {
    height: 30px;
    line-height: 30px;
    padding: 0 12px;
    transition: all 0.2s ease;
    white-space: nowrap;
}

.ql-snow .ql-picker-item:hover {
    background-color: #f1f5f9;
    padding-left: 14px;
}

.ql-snow .ql-picker-item.ql-selected {
    background-color: #e0f2fe;
    color: #0284c7;
    font-weight: 500;
}

/* 选择器按钮样式 */
.ql-snow .ql-picker-label {
    height: 32px;
    line-height: 32px;
    padding: 0 8px;
    border-radius: 4px;
    transition: background-color 0.2s;
}

.ql-snow .ql-picker-label:hover {
    background-color: #f8fafc;
}

/* 字体样式定义 - 确保生效 */
.ql-editor {
    font-size: 16px;
    line-height: 1.6;
}

/* 中文字体样式 */
.ql-editor .ql-font-SimSun {
    font-family: "SimSun", "宋体", serif !important;
}

.ql-editor .ql-font-SimHei {
    font-family: "SimHei", "黑体", sans-serif !important;
}

.ql-editor .ql-font-Microsoft-YaHei {
    font-family: "Microsoft YaHei", "微软雅黑", sans-serif !important;
}

.ql-editor .ql-font-KaiTi {
    font-family: "KaiTi", "楷体", serif !important;
}

.ql-editor .ql-font-FangSong {
    font-family: "FangSong", "仿宋", serif !important;
}

.ql-editor .ql-font-YouYuan {
    font-family: "YouYuan", "幼圆", sans-serif !important;
}

.ql-editor .ql-font-LiSu {
    font-family: "LiSu", "隶书", serif !important;
}

.ql-editor .ql-font-STSong {
    font-family: "STSong", "宋体-繁", serif !important;
}

.ql-editor .ql-font-STZhongsong {
    font-family: "STZhongsong", "中宋-繁", serif !important;
}

.ql-editor .ql-font-STKaiti {
    font-family: "STKaiti", "楷体-繁", serif !important;
}

.ql-editor .ql-font-STFangsong {
    font-family: "STFangsong", "仿宋-繁", serif !important;
}

/* 英文字体样式 */
.ql-editor .ql-font-Arial {
    font-family: "Arial", sans-serif !important;
}

.ql-editor .ql-font-Times-New-Roman {
    font-family: "Times New Roman", serif !important;
}

.ql-editor .ql-font-Courier-New {
    font-family: "Courier New", monospace !important;
}

.ql-editor .ql-font-Verdana {
    font-family: "Verdana", sans-serif !important;
}

.ql-editor .ql-font-Georgia {
    font-family: "Georgia", serif !important;
}

.ql-editor .ql-font-Impact {
    font-family: "Impact", sans-serif !important;
}

.ql-editor .ql-font-Comic-Sans-MS {
    font-family: "Comic Sans MS", cursive !important;
}

.ql-editor .ql-font-sans-serif {
    font-family: "sans-serif" !important;
}

.ql-editor .ql-font-serif {
    font-family: "serif" !important;
}

.ql-editor .ql-font-monospace {
    font-family: "monospace" !important;
}

/* 下拉菜单字体显示 */
.ql-snow .ql-picker.ql-font .ql-picker-label::before,
.ql-snow .ql-picker.ql-font .ql-picker-item::before {
    content: '默认';
}

.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="SimSun"]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="SimSun"]::before {
    content: '宋体';
    font-family: "SimSun", serif;
}

.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="SimHei"]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="SimHei"]::before {
    content: '黑体';
    font-family: "SimHei", sans-serif;
}

.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="Microsoft-YaHei"]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="Microsoft-YaHei"]::before {
    content: '微软雅黑';
    font-family: "Microsoft YaHei", sans-serif;
}

.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="KaiTi"]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="KaiTi"]::before {
    content: '楷体';
    font-family: "KaiTi", serif;
}

.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="FangSong"]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="FangSong"]::before {
    content: '仿宋';
    font-family: "FangSong", serif;
}

.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="YouYuan"]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="YouYuan"]::before {
    content: '幼圆';
    font-family: "YouYuan", sans-serif;
}

.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="LiSu"]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="LiSu"]::before {
    content: '隶书';
    font-family: "LiSu", serif;
}

.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="STSong"]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="STSong"]::before {
    content: '宋体-繁';
    font-family: "STSong", serif;
}

.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="STZhongsong"]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="STZhongsong"]::before {
    content: '中宋-繁';
    font-family: "STZhongsong", serif;
}

.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="STKaiti"]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="STKaiti"]::before {
    content: '楷体-繁';
    font-family: "STKaiti", serif;
}

.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="STFangsong"]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="STFangsong"]::before {
    content: '仿宋-繁';
    font-family: "STFangsong", serif;
}

.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="Arial"]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="Arial"]::before {
    content: 'Arial';
    font-family: "Arial", sans-serif;
}

.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="Times-New-Roman"]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="Times-New-Roman"]::before {
    content: 'Times New Roman';
    font-family: "Times New Roman", serif;
}

.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="Courier-New"]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="Courier-New"]::before {
    content: 'Courier New';
    font-family: "Courier New", monospace;
}

.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="Verdana"]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="Verdana"]::before {
    content: 'Verdana';
    font-family: "Verdana", sans-serif;
}

.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="Georgia"]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="Georgia"]::before {
    content: 'Georgia';
    font-family: "Georgia", serif;
}

.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="Impact"]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="Impact"]::before {
    content: 'Impact';
    font-family: "Impact", sans-serif;
}

.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="Comic-Sans-MS"]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="Comic-Sans-MS"]::before {
    content: 'Comic Sans';
    font-family: "Comic Sans MS", cursive;
}

.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="sans-serif"]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="sans-serif"]::before {
    content: '无衬线';
    font-family: "sans-serif";
}

.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="serif"]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="serif"]::before {
    content: '衬线';
    font-family: "serif";
}

.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="monospace"]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="monospace"]::before {
    content: '等宽';
    font-family: "monospace";
}

/* 字号样式 */
.ql-snow .ql-picker.ql-size .ql-picker-label::before,
.ql-snow .ql-picker.ql-size .ql-picker-item::before {
    content: '16px';
}

.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="8px"]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="8px"]::before {
    content: '8px';
}

.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="10px"]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="10px"]::before {
    content: '10px';
}

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

.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="14px"]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="14px"]::before {
    content: '14px';
}

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

.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="18px"]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="18px"]::before {
    content: '18px';
}

.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="20px"]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="20px"]::before {
    content: '20px';
}

.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="22px"]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="22px"]::before {
    content: '22px';
}

.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="24px"]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="24px"]::before {
    content: '24px';
}

.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="26px"]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="26px"]::before {
    content: '26px';
}

.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="28px"]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="28px"]::before {
    content: '28px';
}

.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="30px"]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="30px"]::before {
    content: '30px';
}

.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="32px"]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="32px"]::before {
    content: '32px';
}

.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="36px"]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="36px"]::before {
    content: '36px';
}

.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="40px"]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="40px"]::before {
    content: '40px';
}

.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="48px"]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="48px"]::before {
    content: '48px';
}

.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="56px"]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="56px"]::before {
    content: '56px';
}

.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="64px"]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="64px"]::before {
    content: '64px';
}

/* 编辑器内容字号样式 */
.ql-editor .ql-size-8px {
    font-size: 8px !important;
}

.ql-editor .ql-size-10px {
    font-size: 10px !important;
}

.ql-editor .ql-size-12px {
    font-size: 12px !important;
}

.ql-editor .ql-size-14px {
    font-size: 14px !important;
}

.ql-editor .ql-size-16px {
    font-size: 16px !important;
}

.ql-editor .ql-size-18px {
    font-size: 18px !important;
}

.ql-editor .ql-size-20px {
    font-size: 20px !important;
}

.ql-editor .ql-size-22px {
    font-size: 22px !important;
}

.ql-editor .ql-size-24px {
    font-size: 24px !important;
}

.ql-editor .ql-size-26px {
    font-size: 26px !important;
}

.ql-editor .ql-size-28px {
    font-size: 28px !important;
}

.ql-editor .ql-size-30px {
    font-size: 30px !important;
}

.ql-editor .ql-size-32px {
    font-size: 32px !important;
}

.ql-editor .ql-size-36px {
    font-size: 36px !important;
}

.ql-editor .ql-size-40px {
    font-size: 40px !important;
}

.ql-editor .ql-size-48px {
    font-size: 48px !important;
}

.ql-editor .ql-size-56px {
    font-size: 56px !important;
}

.ql-editor .ql-size-64px {
    font-size: 64px !important;
}
</style>

四、使用

// 使用
<quill-markdown v-model="articleForm.content" :height="600" :max-image-size="5"
       :max-video-size="100" @image-uploaded="handleImageUploaded"
       @video-uploaded="handleVideoUploaded"></quill-markdown>

// 引入
import quillMarkdown from '../../components/quill-Markdown.vue'
// 注册
    components: {
        quillMarkdown
    },
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值