<template>
<div>
<quill-editor v-model="content" ref="myQuillEditor" :options="editorOption" @change="onEditorChange"
@input="handleInput"></quill-editor>
<!-- 链接添加对话框 -->
<el-dialog title="添加链接" :visible.sync="linkDialogVisible" width="30%" :close-on-click-modal="false">
<el-form ref="linkForm" :model="linkForm" label-width="80px">
<el-form-item label="链接地址">
<el-input v-model="linkForm.url" placeholder="请输入链接地址,例如:http://" autocomplete="off"
@blur="validateLink(linkForm.url.trim())"></el-input>
</el-form-item>
<el-form-item label="备注" style="margin-top: 10px;margin-bottom: 10px;">
<el-input v-model="linkForm.text" placeholder="请输入链接备注" :disabled="!linkForm.url"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleLinkSubmit">确认</el-button>
<el-button @click="closeLinkDialog">取消</el-button>
</el-form-item>
</el-form>
</el-dialog>
<!-- 图片设置对话框 -->
<el-dialog title="插入图片" :visible.sync="imageDialogVisible" width="25%" :close-on-click-modal="false" @close="closeImageDialog"
class="pic-dialog">
<el-tabs v-model="activeTab" ref="imageTabs">
<el-tab-pane label="本地图片" name="localImage">
<el-form :model="localImageForm" label-width="80px">
<el-form-item>
<el-upload ref="imageUpload" class="upload-demo" :http-request="uploadToCOS"
:on-success="handleImageSuccess" :on-error="handleError" accept="image/*"
:on-change="handleImageChange" action="#" :show-file-list="false"
:on-progress="handleImageUploadProgress">
<div class="image-item">
<el-image v-if="localImageForm.imageUrl" :src="localImageForm.imageUrl"
fit="contain" slot="trigger">
</el-image>
<img v-else src="@/assets/default-image.jpg" alt="Upload Failed Image">
</div>
</el-upload>
<el-progress :percentage="uploadImagePercentage" style="margin-bottom: 10px;width:200px"></el-progress>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="insertLocalImages">确认</el-button>
<el-button @click="closeImageDialog">取消</el-button>
</el-form-item>
</el-form>
</el-tab-pane>
<el-tab-pane label="链接图片" name="urlImage">
<el-form :model="urlImageForm" label-width="80px">
<el-form-item label="图片链接">
<el-input v-model="urlImageForm.url" placeholder="请输入图片链接" autocomplete="off"></el-input>
<div class="image-item" style="margin-bottom: 20px;">
<el-image v-if="urlImageForm.url" :src="urlImageForm.url" fit="contain"
></el-image>
<img v-else src="@/assets/default-image.jpg" alt="Upload Failed Image">
</div>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="insertURLImage">确认</el-button>
<el-button @click="closeImageDialog">取消</el-button>
</el-form-item>
</el-form>
</el-tab-pane>
</el-tabs>
</el-dialog>
<!-- 视频设置对话框 -->
<el-dialog title="插入视频" :visible.sync="videoDialogVisible" width="25%" :close-on-click-modal="false" @close="closeVideoDialog"
>
<el-tabs v-model="activeVideoTab" ref="videoTabs">
<el-tab-pane label="本地视频" name="localVideo">
<el-form :model="localVideoForm" label-width="80px">
<el-form-item label="视频文件" style="margin-top: 10px;margin-bottom: 20px;">
<!-- 视频上传 -->
<el-upload ref="videoUpload" class="upload-demo" :http-request="uploadToCOS"
:on-success="handleVideoSuccess" :on-error="handleError" :auto-upload="false"
:on-progress="handleUploadProgress" :show-file-list="false" accept="video/*"
:on-remove="handleVideoRemove" :on-change="handleVideoChange" action="#">
<el-button slot="trigger" size="small" type="success"
style="width:300px">打开并上传</el-button>
<div class="video-item">
<video v-if="localVideoForm.videoUrl" :src="localVideoForm.videoUrl"
controls="controls" width="300px" height="150px"></video>
<div slot="tip" class="el-upload__tip"></div>
</div>
<el-progress :percentage="uploadVideoPercentage" style="width:355px"></el-progress>
</el-upload>
</el-form-item>
<el-form-item label="设置宽度" style="margin-bottom: 20px;">
<el-input v-model.number="localVideoForm.width" placeholder="请输入宽度"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="insertLocalVideo">确认</el-button>
<el-button @click="closeVideoDialog">取消</el-button>
</el-form-item>
</el-form>
</el-tab-pane>
<el-tab-pane label="视频链接" name="urlVideo">
<el-form :model="urlVideoForm" label-width="80px">
<el-form-item label="视频链接" style="margin-top: 10px;margin-bottom: 20px;">
<el-input v-model="urlVideoForm.url" placeholder="请输入视频链接,例如:http://" autocomplete="off"
@blur="validateLink(urlVideoForm.url.trim())"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="insertURLVideo">确认</el-button>
<el-button @click="closeVideoDialog">取消</el-button>
</el-form-item>
</el-form>
</el-tab-pane>
</el-tabs>
</el-dialog>
</div>
</template>
<script>
import { quillEditor } from "vue-quill-editor";
import { Quill } from "vue-quill-editor";
import resizeImage from "quill-image-resize-module";
import { ImageDrop } from "quill-image-drop-module";
import "quill/dist/quill.core.css";
import "quill/dist/quill.snow.css";
import "quill/dist/quill.bubble.css";
Quill.register("modules/imageResize", resizeImage);
Quill.register("modules/imageDrop", ImageDrop);
Quill.register("modules/resizeImage", resizeImage);
import "@/styles/quillEditor.css"
import { titleConfig, toolbarOptions } from "@/js/quillEditor";
import COS from 'cos-js-sdk-v5';
import { v4 as uuidv4 } from 'uuid';
// 扩展Quill以支持视频嵌入
const BlockEmbed = Quill.import('blots/block/embed');
class VideoBlot extends BlockEmbed {
static create(value) {
let node = super.create();
node.setAttribute('src', value.url);
node.setAttribute('controls', true);
node.setAttribute('width', value.width || '50%');
node.setAttribute('height', value.height || 'auto');
return node;
}
static value(node) {
return {
url: node.getAttribute('src'),
width: node.getAttribute('width'),
height: node.getAttribute('height')
};
}
}
VideoBlot.blotName = 'video';
VideoBlot.tagName = 'video';
Quill.register(VideoBlot);
export default {
components: {
quillEditor,
},
data() {
return {
content: "",
editorOption: {
modules: {
toolbar: {
container: toolbarOptions,
handlers: {
image: this.openImageDialog,
link: this.openLinkDialog,
video: this.openVideoDialog
},
},
imageDrop: true,
imageResize: {
displayStyles: {
backgroundColor: "black",
border: "none",
color: "white",
},
modules: ["Resize", "DisplaySize", "Toolbar"],
},
},
placeholder: "请输入正文....",
theme: "snow",
},
linkDialogVisible: false,
linkForm: {
url: 'https://',
text: '',
},
currentRange: null, // 保存当前选区信息
imageDialogVisible: false,
videoDialogVisible: false,
activeTab: 'localImage', // 默认选中本地图片
activeVideoTab: 'localVideo', // 默认选中本地视频
localImageForm: {
file: null,
imageUrl: '', // 用于显示选中的本地图片
},
urlImageForm: {
url: '',
},
localVideoForm: {
file: null,
videoUrl: '',
width: '',
},
urlVideoForm: {
url: 'https://',
width: '',
},
file: null,
editorDialogVisible: false,
htmlData: '',
cos: null, // 用于存储COS实例
uploadVideoPercentage: 0,
uploadImagePercentage:0,
urlVideoUrl:''
};
},
created() {
// 初始化COS实例
this.cos = new COS({
SecretId: '', // 替换为你的SecretId
SecretKey: '', // 替换为你的SecretKey
});
},
methods: {
urlImageFormInput() {
console.log("是否获取焦点")
},
uploadToCOS({ file, onProgress, onSuccess, onError }) {
// 生成唯一的文件名
const uniqueFileName = this.generateUniqueFileName(file.name);
this.cos.uploadFile({
Bucket: '', // 替换为你的Bucket
Region: '', // 替换为你的Region
Key: uniqueFileName, // 使用生成的唯一文件名
Body: file,
SliceSize: 1024 * 1024, // 分块大小,单位为字节,这里设置为1MB
onProgress: function (progressData) {
onProgress(progressData);
}
}, (err, data) => {
if (err) {
onError(err);
} else {
onSuccess(data);
}
});
},
// 打开本地图片、视频、文件
previewFile(file) {
const reader = new FileReader();
reader.readAsDataURL(file);
},
// 生成唯一文件名
generateUniqueFileName(originalName) {
// 获取文件扩展名
const extension = originalName.substring(originalName.lastIndexOf('.'));
// 生成唯一文件名
const uniqueName = uuidv4();
// 返回新的文件名
return `${uniqueName}${extension}`;
},
// 提交上传本地图片、视频、文件
submitUpload(refName) {
this.$refs[refName].submit();
},
/* eslint-disable */
handleError(err, file) {
console.error('上传失败:', err);
},
handleInput() {
// 输入内容后,隐藏错误信息
this.$emit('input', this.content.trim());
},
/* eslint-disable */
onEditorChange({ quill, html, text }) {
this.content = html;
},
setTitleConfig() {
for (const item of titleConfig) {
const tip = document.querySelector(".quill-editor " + item.Choice);
if (!tip) continue;
tip.setAttribute("title", item.title);
}
},
// 打开插入链接对话框 *********************************************************************************
openLinkDialog() {
const quill = this.$refs.myQuillEditor.quill;
if (!quill) {
console.error('Quill instance not found');
return;
}
// 获取当前选区
this.currentRange = quill.getSelection();
if (!this.currentRange) {
console.error('Selection not found');
return;
}
// 重新打开对话框时清空输入框
this.linkForm.url = 'https://';
this.linkForm.text = '';
this.linkDialogVisible = true;
},
// 关闭插入链接对话框
closeLinkDialog() {
this.linkDialogVisible = false;
},
handleLinkSubmit() {
const quill = this.$refs.myQuillEditor.quill;
if (!quill) {
console.error('Quill instance not found');
return;
}
const { url, text } = this.linkForm;
if (!this.currentRange) {
console.error('Current range not found');
return;
}
console.log("如果有备注文本,则插入带备注的链接");
// 如果有备注文本,则插入带备注的链接
if (text) {
this.$nextTick(() => {
const linkHtml = `<a href="${url}" title="${text}">${text}</a>`;
quill.clipboard.dangerouslyPasteHTML(this.currentRange.index, linkHtml, 'user');
this.linkDialogVisible = false;
});
} else {
// 否则直接插入普通链接
this.$nextTick(() => {
const linkHtml = `<a href="${url}">${url}</a>`;
quill.clipboard.dangerouslyPasteHTML(this.currentRange.index, linkHtml, 'user');
this.linkDialogVisible = false;
});
}
// 更新内容
this.content = quill.root.innerHTML;
},
validateLink(url) {
// 校验链接格式
// const url = this.linkForm.url.trim();
if (url && !this.validateURL(url)) {
this.$message.error('链接地址格式不正确,请输入有效的链接地址。');
}
},
validateURL(url) {
// 修正后的正则表达式用于验证链接格式,支持 http 和 https 协议
const urlPattern = /^(https?:\/\/)?[\w.-]+\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_+.~#?&//=]*)?$/;
return urlPattern.test(url);
},
// 打开插入图片对话框 *********************************************************************************
openImageDialog() {
// 获取当前光标位置
const quill = this.$refs.myQuillEditor.quill;
if (quill) {
this.currentRange = quill.getSelection();
}
if (!this.currentRange) {
return;
}
this.imageDialogVisible = true;
// 在下一次DOM更新后模拟点击本地图片选项卡
this.$nextTick(() => {
const tabs = this.$refs.imageTabs;
if (tabs) {
tabs.setCurrentName('localImage');
}
});
},
// 关闭插入图片对话框
closeImageDialog() {
this.imageDialogVisible = false;
// 重置表单
this.localImageForm.file = null;
this.localImageForm.imageUrl = '';
this.urlImageForm.url = '';
this.uploadImagePercentage = 0;
},
// 2.1 插入本地图片
insertLocalImages() {
const { imageUrl } = this.localImageForm;
if (!imageUrl) {
return;
}
// 直接使用上传后的URL调用insertImage方法
this.insertImage(imageUrl);
},
/* eslint-disable */
handleImageSuccess(response, file) {
console.log('图片上传成功:', response);
const fileUrl = `https://${response.Location}`;
this.localImageForm.imageUrl = fileUrl;
// this.$refs.imageUpload.clearFiles(); //去掉文件列表
},
handleImageChange(file) {
if (file.raw) {
this.file = file.raw; // 获取选择的文件对象
this.previewFile(file.raw); // 预览图片
this.submitUpload('imageUpload');
}
},
handleImageRemove() {
this.localImageForm.imageUrl = ''; // 重置视频文件
},
handleImageUploadProgress(event, file, fileList) {
this.uploadImagePercentage = Math.round(event.loaded / event.total * 100);
},
// 2.2 插入链接图片
insertURLImage() {
const { url} = this.urlImageForm;
this.insertImage(url);
},
// 2.3 图片嵌入到富文本
insertImage(url) {
const quill = this.$refs.myQuillEditor.quill;
if (!quill) {
console.error('Quill实例未找到');
return;
}
const range = this.currentRange;
// quill.clipboard.dangerouslyPasteHTML(range.index, `<img src="${url}" style="width: ${width}px; height: ${height}px;">`, 'user');
quill.clipboard.dangerouslyPasteHTML(range.index, `<img src="${url}">`, 'user');
this.content = quill.root.innerHTML;
// 调整插入的图片大小并设置id
this.$nextTick(() => {
const imgTags = quill.root.querySelectorAll('img');
imgTags.forEach((img, index) => {
if (!img.id) {
const imageId = `img-${Date.now()}-${index}`;
img.setAttribute('id', imageId);
}
});
});
// 插入后重置对话框和表单
this.closeImageDialog();
},
adjustEditorHeight() {
const quill = this.$refs.myQuillEditor.quill;
if (!quill) return;
const editorElement = quill.root;
if (!editorElement) return;
editorElement.style.minHeight = "500px";
},
// 视频设置 *********************************************************************************
// 打开插入视频对话框
openVideoDialog() {
// 获取当前光标位置
const quill = this.$refs.myQuillEditor.quill;
if (quill) {
this.currentRange = quill.getSelection();
}
if (!this.currentRange) {
return;
}
this.videoDialogVisible = true;
// 在下一次DOM更新后模拟点击本地图片选项卡
this.$nextTick(() => {
const tabs = this.$refs.videoTabs;
if (tabs) {
tabs.setCurrentName('localVideo');
}
});
},
// 关闭插入视频对话框
closeVideoDialog() {
this.videoDialogVisible = false;
// 重置表单
this.localVideoForm.file = null;
this.localVideoForm.videoUrl = '';
this.localVideoForm.width = '';
this.urlVideoForm.url = '';
this.urlVideoForm.width = '';
// this.$refs.videoUpload.clearFiles(); // 清除上传文件列表
this.uploadVideoPercentage = 0;
},
// 3.1 插入本地视频
insertLocalVideo() {
const { videoUrl, width } = this.localVideoForm;
if (!videoUrl) {
return;
}
// 直接使用上传后的URL调用insertVideo方法
this.insertVideo(videoUrl, width);
},
handleVideoSuccess(response, file) {
console.log('视频上传成功:', response);
const fileUrl = `https://${response.Location}`;
this.localVideoForm.videoUrl = fileUrl;
},
handleError(err, file) {
console.error('上传失败:', err);
},
handleVideoChange(file) {
if (file.raw) {
this.file = file.raw; // 获取选择的文件对象
this.previewFile(file.raw); // 预览视频
}
this.submitUpload('videoUpload')
},
handleVideoRemove() {
this.localVideoForm.videoUrl = null; // 重置视频文件
},
handleUploadProgress(event, file, fileList) {
this.uploadVideoPercentage = Math.round(event.loaded / event.total * 100);
},
// 3.2 插入链接视频
insertURLVideo() {
const { url, width } = this.urlVideoForm;
this.insertVideo(url, width);
},
// 3.3 插入视频到富文本中
insertVideo(url, width) {
const quill = this.$refs.myQuillEditor.quill;
if (!quill) {
console.error('Quill实例未找到');
return;
}
const range = this.currentRange;
const index = range ? range.index : quill.getLength();
quill.insertEmbed(index, 'video', {
url: url,
width: width,
});
this.content = quill.root.innerHTML;
this.closeVideoDialog();
},
},
mounted() {
this.setTitleConfig();
},
};
</script>
<style scoped>
/* 可以添加自定义样式 */
.image-item {
margin-top: 20px;
width: 150px;
height: 150px;
overflow: hidden;
border: 2px dashed #ccc;
background-color: white;
display: flex;
justify-content: center;
align-items: center;
position: relative;
cursor: pointer;
/* margin-bottom: 20px; */
}
.video-item {
margin-top: 20px;
width: 300px;
height: 150px;
overflow: hidden;
border: 2px dashed #ccc;
background-color: white;
display: flex;
justify-content: center;
align-items: center;
position: relative;
cursor: pointer;
}
.progress-bar {
width: 300px;
height: 10px;
background-color: #f0f0f0;
margin-top: 10px;
}
.progress-bar-inner {
height: 100%;
background-color: #409eff;
}
</style>
<style scoped>
.pic-dialog {
.el-dialog__header {
border-bottom: none;
}
.el-dialog__body {
padding-top: 0;
margin-right: 10px;
}
.dialog-content {
padding: 0 40px;
}
.el-dialog__footer {
padding: 10px 10px 10px;
border-top: none;
}
}
.ql-editor.ql-blank /deep/ {
min-height: 500px !important;
/* 设置空内容时的最小高度 */
}
.quill-editor {
line-height: normal;
}
</style>
quillEditor.css
/* 字体风格 */
/* 处理下拉字体选择器中选项的文本溢出并显示省略号 */
.ql-snow .ql-picker.ql-font .ql-picker-label::before {
width: 88px; /* 设置下拉选项宽度,可以根据需要调整 */
white-space: nowrap; /* 不换行显示 */
overflow: hidden; /* 隐藏溢出部分 */
text-overflow: ellipsis; /* 使用省略号显示溢出文本 */
}
.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";
}
.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";
}
.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";
}
.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";
}
.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";
}
.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";
}
.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";
}
.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: "sans-serif";
font-family: "sans-serif";
}
.ql-font-SimSun { font-family: "SimSun"; }
.ql-font-SimHei { font-family: "SimHei"; }
.ql-font-Microsoft-YaHei { font-family: "Microsoft YaHei"; }
.ql-font-KaiTi { font-family: "KaiTi"; }
.ql-font-FangSong { font-family: "FangSong"; }
.ql-font-Arial { font-family: "Arial"; }
.ql-font-Times-New-Roman { font-family: "Times New Roman"; }
.ql-font-sans-serif { font-family: "sans-serif"; }
/* 字体大小 */
.ql-snow .ql-picker.ql-size .ql-picker-label::before { content: "字体大小"; }
.ql-snow .ql-picker.ql-size .ql-picker-item::before { content: "常规"; }
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="14px"]::before{
content: "14px";
font-size: 14px;
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="16px"]::before{
content: "16px";
font-size: 14px;
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="18px"]::before{
content: "18px";
font-size: 14px;
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="20px"]::before{
content: "20px";
font-size: 14px;
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="22px"]::before{
content: "22px";
font-size: 14px;
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="26px"]::before{
content: "26px";
font-size: 14px;
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="30px"]::before {
content: "30px";
font-size: 14px;
}
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="14px"]::before {
content: "14px";
font-size: 14px;
}
.ql-size-14px { font-size: 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";
font-size: 16px;
}
.ql-size-16px { font-size: 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";
font-size: 18px;
}
.ql-size-18px { font-size: 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";
font-size: 20px;
}
.ql-size-20px { font-size: 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";
font-size: 22px;
}
.ql-size-22px { font-size: 22px; }
/* .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";
font-size: 26px;
}
.ql-size-26px { font-size: 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";
font-size: 28px;
}
.ql-size-28px { font-size: 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";
font-size: 30px;
}
.ql-size-30px { font-size: 30px; }
/* 段落大小 */
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="1"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="1"]::before {
content: "标题1";
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="2"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="2"]::before {
content: "标题2";
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="3"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="3"]::before {
content: "标题3";
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="4"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="4"]::before {
content: "标题4";
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="5"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="5"]::before {
content: "标题5";
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="6"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="6"]::before {
content: "标题6";
}
.ql-snow .ql-picker.ql-header .ql-picker-item::before {
content: "常规";
}
/* .ql-snow .ql-picker.ql-header .ql-picker-label[data-value="1"]::before, */
.ql-snow .ql-picker.ql-header .ql-picker-label::before {
content: "标题大小";
}
/* 默认设置 */
.ql-snow .ql-editor { font-size: 14px; }
/* 查看样式 */
.view-editor .ql-toolbar { display: none; }
.view-editor .ql-container.ql-snow { border: 0; }
.view-editor .ql-container.ql-snow .ql-editor { padding: 0; }
/* 编辑样式 */
.edit-editor .ql-toolbar { display: block; }
.edit-editor .ql-container.ql-snow {
border: 1px solid #ccc;
min-height: inherit;
}
quillEditor.js
import { Quill } from "vue-quill-editor";
// 自定义字体大小
const sizes = [false,"14px","16px","18px","20px","22px","26px","28px","30px",];
const Size = Quill.import("formats/size");
Size.whitelist = sizes;
// 自定义字体
const fonts = ["SimSun","SimHei","Microsoft-YaHei","KaiTi","FangSong","Arial","Times-New-Roman","sans-serif",];
var Font = Quill.import("formats/font");
Font.whitelist = fonts;
Quill.register(Font, true);
// 工具栏相关配置
export const toolbarOptions = [
["bold", "italic", "underline"], // 加粗 斜体 下划线 删除线
[{ size: sizes }], // 字体大小
[{ header: [1, 2, 3, 4, 5, false] }], // 标题
[{ color: [] }, { background: [] }], // 字体颜色、字体背景颜色
// [{ font: fonts }], // 字体种类
["link", "image", "video","clean"], // 链接、图片、视频
];
// 设置工具栏中文提示
export const titleConfig = [
{ Choice: ".ql-insertMetric", title: "跳转配置" },
{ Choice: ".ql-bold", title: "加粗" },
{ Choice: ".ql-italic", title: "斜体" },
{ Choice: ".ql-header", title: "段落格式" },
{ Choice: ".ql-strike", title: "删除线" },
// { Choice: ".ql-font", title: "字体" },
{ Choice: ".ql-align", title: "对齐方式" },
{ Choice: ".ql-color", title: "字体颜色" },
{ Choice: ".ql-background", title: "背景颜色" },
{ Choice: ".ql-image", title: "图像" },
{ Choice: ".ql-video", title: "视频" },
{ Choice: ".ql-link", title: "添加链接" },
{ Choice: ".ql-clean", title: "清除字体格式" },
{ Choice: ".ql-size .ql-picker-item:nth-child(2)", title: "标准" },
];