基于 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.quillconst range = quill.getSelection()const insertIndex = range ? range.index : quill.getLength() - 1quill.insertEmbed(insertIndex, 'custom-video', this.getImageUrl(videoUrl))// 设置视频属性this.$nextTick(() => {const lastIndex = quill.getLength() - 1const [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 * 1024if (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},

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/918908.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/918908.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C#内嵌字符串格式化输出

内嵌字符串格式输出 double speedOfLight 299792.458;System.Globalization.CultureInfo.CurrentCulture System.Globalization.CultureInfo.GetCultureInfo("nl-NL"); string messageInCurrentCulture $"The speed of light is {speedOfLight:N3} km/s.&quo…

ThreeJS程序化生成城市大场景底座(性能测试)

一、简介基于矢量geojson数据构建建筑、植被、道路等&#xff0c;实现城市场景底座。涉及渲染的性能优化无非就是众所周知的那些事儿。视锥剔除、mesh合并、减少draw call、四叉树、八叉树、数据压缩、WebWorker、着色器优化等。下面是对东莞市数十万建筑以及海量3D树的渲染测试…

​电风扇离线语音芯片方案设计与应用场景:基于 8 脚 MCU 与 WTK6900P 的创新融合

​电风扇离线语音芯片方案设计与应用场景&#xff1a;基于 8 脚 MCU 与 WTK6900P 的创新融合一、引言在智能家居领域蓬勃发展的当下&#xff0c;用户对于家电产品的智能化和便捷性需求日益增长。传统的电风扇控制方式&#xff0c;如按键操作或遥控器控制&#xff0c;在某些场景…

(第四篇)spring cloud之Consul注册中心

目录 一、介绍 二、安装 三、整合代码使用 1、创建服务提供者8006 2、创建服务消费者80 3、Eureka、zookeeper和consul的异同点 一、介绍 Consul 是一套开源的分布式服务发现和配置管理系统&#xff0c;由 HashiCorp 公司用 Go 语言开发。它提供了微服务系统中的服务治理…

NAT 和 PNAT

核心概念与背景 IPv4 地址枯竭&#xff1a; IPv4 地址空间有限&#xff08;约 42.9 亿个&#xff09;&#xff0c;早已分配殆尽。NAT/PNAT 是缓解此问题的最重要、最广泛部署的技术。私有 IP 地址空间&#xff1a; IANA 保留了三个 IPv4 地址段专供私有网络内部使用&#xff08…

windows系统创建FTP服务

一丶开启FTP功能 控制面板->程序与功能->启用或关闭windows功能->Internet Information Services->勾选FTP服务器二丶创建FTP服务 1丶控制面板->windows工具->Internet Information Services (IIS) 管理器2丶网站->添加FTP站点->输入对应内容3丶点击新…

DeepSeek补全IBM MQ 9.4 REST API 执行命令的PPT

DeepSeek补全了我在网上找到的PPT的一页内容&#xff0c;帮了大忙了。人机协同&#xff0c;人工智能可以协助人更好的做事。下面的内容是讲解IBM MQ REST API 执行IBM MQ命令的PPT: MQSC for REST Tailored RESTful support for individual MQ objects and actions are in the …

【swift】SwiftUI动画卡顿全解:GeometryReader滥用检测与Canvas绘制替代方案

SwiftUI动画卡顿全解&#xff1a;GeometryReader滥用检测与Canvas绘制替代方案一、GeometryReader的性能陷阱深度解析1. 布局计算机制2. 动画中的灾难性表现二、GeometryReader滥用检测系统1. 静态代码分析器2. 运行时性能监控三、Canvas绘制优化方案1. 基础Canvas实现2. 性能优…

悄悄话、合唱层次感:声网空间音频解锁语聊新玩法

作为语聊房主播&#xff0c;我曾觉得线上相聚差点意思。多人开麦时声音混杂&#xff0c;互动缺真实感&#xff0c;观众留不住&#xff0c;自己播着也没劲。直到平台接入声网空间音频&#xff0c;一切改观&#xff0c;观众说像在真实房间聊天&#xff0c;留存率涨 35%&#xff0…

【工具】多图裁剪批量处理工具

文章目录工具核心功能亮点1. 批量上传与智能管理2. 精准直观的裁剪控制3. 一键应用与批量处理为什么这个工具能提升你的工作效率&#xff1f;统一性与一致性保证节省90%以上的时间专业级功能&#xff0c;零学习成本实际应用场景电子商务摄影工作内容创作教育领域技术优势完全在…

如何提升需求分析能力

要系统性地提升需求分析能力&#xff0c;核心在于实现从一个被动的“需求记录员”&#xff0c;向一个主动的、价值驱动的“业务问题解决者”的深刻转型。要完成这一蜕变&#xff0c;必须在五个关键领域进行系统性的修炼与实践&#xff1a;培养“穿透表象”的系统思维能力、掌握…

另类的pdb恢复方式

cdb中有pdb1,pdb2 需求&#xff1a;希望将在线热备份pdb1的备份集a&#xff0c;恢复成pdb3&#xff0c;使得cdb中有pdb1,2,3 参考到的&#xff1a;RMAN备份恢复典型案例——跨平台迁移pdb - 墨天轮 ORA-65122: Pluggable Database GUID Conflicts With The GUID Of An Existi…

HarmonyOS 实战:用 @Observed + @ObjectLink 玩转多组件实时数据更新

摘要 在鸿蒙&#xff08;HarmonyOS&#xff09;应用开发中&#xff0c;实时数据更新是一个绕不开的话题&#xff0c;尤其是在你封装了很多自定义组件、需要多个组件之间共享和同步数据的场景里。过去我们可能会依赖父子组件直接传参或全局状态管理&#xff0c;但这样写会让代码…

云原生俱乐部-杂谈2

说实话&#xff0c;杂谈系列可能会比较少&#xff0c;因为毕竟大部分时间都是上的线上&#xff0c;迄今为止也是&#xff0c;和雷老师与WH的交流不是很多。这个系列仅仅是我在做其他笔记部分无聊的时候来写的&#xff0c;内容也没有规划过&#xff0c;随想随写。倒不是时间太多…

波浪模型SWAN学习(1)——模型编译与波浪折射模拟(Test of the refraction formulation)

SWAN模型编译与波浪折射模拟&#xff08;Test of the refraction formulation&#xff09;编译过程算例简介参数文件文件头&#xff08;HEADING&#xff09;计算区域和网格地形数据边界条件物理模块设置输出设置执行参数模拟结果由于工作原因&#xff0c;最近开始接触波浪模型&…

更换cmd背景图片

打开cmd 右击顶部&#xff0c;选择设置选择命令提示符&#xff0c;外观选择背景图像路径更改成自己的图片&#xff0c;然后右下角保存 设置成功

基于RobustVideoMatting(RVM)进行视频人像分割(torch、onnx版本)

发表时间&#xff1a;2021年8月25日 项目地址&#xff1a;https://peterl1n.github.io/RobustVideoMatting/ 论文阅读&#xff1a;https://hpg123.blog.csdn.net/article/details/134409222 RVM是字节团队开源的一个实时人像分割模型&#xff0c;基于LSTMConv实现&#xff0c;…

强制从不抱怨环境。

警世俗语&#xff1a;强者逆袭心法&#xff08;句句穿心&#xff09;环境是泥潭&#xff1f;那就让它开出金莲&#xff01; —— 抱怨是弱者的裹脚布&#xff0c;行动是强者的登天梯。烂泥里也能种出摇钱树&#xff0c;关键看你敢不敢下手挖&#xff01;老天爷发牌烂&#xff1…

MC0439符号统计

码蹄集OJ-符号统计 MC0439・符号统计 难度&#xff1a;黄金 时间限制&#xff1a;1 秒 占用内存&#xff1a;256 M 收藏 报错 在华容道放曹的紧张时刻&#xff0c;小码哥接到了一个看似微不足道却至关重要的任务&#xff1a;解读一条仅由小写英文字母组成的神秘字符串 s&#…

Android Jetpack 系列(五)Room 本地数据库实战详解

1. 简介 在需要轻量级本地持久化的场景中&#xff0c;DataStore 是一个理想的选择&#xff08;详见《Android Jetpack 系列&#xff08;四&#xff09;DataStore 全面解析与实践》&#xff09;。但当你面临如下需求时&#xff0c;本地数据库便显得尤为重要&#xff1a; 复杂的…