基于 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
},
posted on 2025-08-16 20:17  ljbguanli  阅读(58)  评论(0)    收藏  举报