Quilleditor.vue
<template>
<div id="Quill" class="ql-editor">
<quill-editor
v-model="content"
ref="myQuillEditor"
@blur="onEditorBlur($event)"
@focus="onEditorFocus($event)"
@change="onEditorChange($event)"
:options="editorOption"
>
<!-- 自定义toolar -->
<div id="toolbar" slot="toolbar">
<!-- Add a bold button -->
<button class="ql-bold" title="加粗">Bold</button>
<button class="ql-italic" title="斜体">Italic</button>
<button class="ql-underline" title="下划线">underline</button>
<button class="ql-strike" title="删除线">strike</button>
<button class="ql-blockquote" title="引用"></button>
<button class="ql-code-block" title="代码"></button>
<button class="ql-header" value="1" title="标题1"></button>
<button class="ql-header" value="2" title="标题2"></button>
<!--Add list -->
<button class="ql-list" value="ordered" title="有序列表"></button>
<button class="ql-list" value="bullet" title="无序列表"></button>
<!-- Add font size dropdown -->
<select
class="ql-header"
title="段落格式"
style="line-height: initial;"
>
<option selected>段落</option>
<option value="1">标题1</option>
<option value="2">标题2</option>
<option value="3">标题3</option>
<option value="4">标题4</option>
<option value="5">标题5</option>
<option value="6">标题6</option>
</select>
<select
class="ql-size fontSize"
title="字体大小"
style="line-height: initial;"
>
<option
v-for="item in fontSizeArr"
:value="item.value"
:key="item.value"
>{{ item.value }}</option
>
</select>
<select class="ql-font" title="字体" style="line-height: initial;">
<option value="SimSun">宋体</option>
<option value="SimHei">黑体</option>
<option value="Microsoft-YaHei">微软雅黑</option>
<option value="KaiTi">楷体</option>
<option value="FangSong">仿宋</option>
<option value="Arial">Arial</option>
</select>
<!-- Add subscript and superscript buttons -->
<select class="ql-color" value="color" title="字体颜色"></select>
<select
class="ql-background"
value="background"
title="背景颜色"
></select>
<select class="ql-align" value="align" title="对齐"></select>
<select class="ql-lineHeight">
<option
v-for="(item, index) in lineHeight"
:key="index"
:value="item"
:selected="index === 0"
>{{ item }}</option
>
</select>
<!-- <select title="文字行高" class="ql-line-height">
<option selected></option>
<option value="1">a</option>
</select> -->
<button
id="custom-button"
@click.prevent="videoHandler"
title="图片"
style="margin: 0 0 0 49px;"
>
<span>图</span>
</button>
<!-- <button id="custom-button" @click.prevent="videoHandler" title="视频">
<Icon type="md-play" />
</button>-->
<button class="ql-clean" title="还原"></button>
<!-- You can also add your own -->
</div>
</quill-editor>
<!-- <div class="limit">
当前已输入 <span>{{ nowLength }}</span> 个字符,您还可以输入
<span>{{ SurplusLength }}</span> 个字符。
</div>
:action="'/api/manage/ueditor/ueditorVideo'"
-->
<Upload
:action="$HTTPURL + this.uploadUrl"
:before-upload="beforeUpload"
:data="uploadData"
:on-success="uploadSuccess"
style="display:none"
ref="upload"
>
<Button icon="ios-cloud-upload-outline" id="imgInput">点击上传</Button>
</Upload>
</div>
</template>
<script>
import { quillRedefine } from "vue-quill-editor-upload";
import VueQuillEditor, { Quill } from "vue-quill-editor";
import { ImageDrop } from "quill-image-drop-module";
import ImageResize from "quill-image-resize-module";
import Parchment from 'parchment';
import lineHeight from './lineHeight';
Quill.register("modules/imageDrop", ImageDrop);
Quill.register("modules/imageResize", ImageResize);
let fontSizeStyle = Quill.import("attributors/style/size");
fontSizeStyle.whitelist = [
"16px",
"12px",
"14px",
"18px",
"20px",
"22px",
"24px",
"26px",
"28px",
"30px",
"32px",
"34px",
"36px",
"38px",
"40px"
];
Quill.register(fontSizeStyle, true);
export default {
name: "Quilleditor",
props: {
formData: {
type: Object,
default: () => {
return {};
}
}
},
data() {
return {
lineHeight: ['1', '1.1','1.2','1.3','1.4','1.5','1.6','1.7','1.8','1.9','2','2.1','2.2','2.3','2.4','2.5','2.6','2.7','2.8','2.9','3'],
fontSizeArr: [
{ value: "16px" },
{ value: "12px" },
{ value: "14px" },
{ value: "18px" },
{ value: "20px" },
{ value: "22px" },
{ value: "24px" },
{ value: "26px" },
{ value: "28px" },
{ value: "30px" },
{ value: "32px" },
{ value: "34px" },
{ value: "36px" },
{ value: "38px" },
{ value: "40px" }
],
content: "",
editorOption: {},
uploadUrl: "/ueditor/ueditorImage",
uploadData: {
tableType: ""
},
// 上传七牛的actiond地址
get qnLocation() {
return "/api/manage/housesMain/uploadVideo";
}
};
},
created() {
this.editorOption = quillRedefine({
// 图片上传的设置
uploadConfig: {
action: this.$HTTPURL + this.uploadUrl,
// 必填参数 图片上传地址
// 必选参数 res是一个函数,函数接收的response为上传成功时服务器返回的数据
// 你必须把返回的数据中所包含的图片地址 return 回去
res: respnse => {
return respnse.data.originalImagePath;
},
methods: "POST", // 可选参数 图片上传方式 默认为post // 可选参数 如果需要token验证,假设你的token有存放在sessionStorage
/* token: sessionStorage.token,*/ name: "file", // 可选参数 文件的参数名 默认为img // 可选参数 图片限制大小,单位为Kb, 1M = 1024Kb
/* size: 500,*/ accept:
"image/png, image/gif, image/jpeg, image/bmp, image/x-icon", // 可选参数 可上传的图片格式
// input点击事件 formData是提交的表单实体
// 图片上传参数名
change: formData => {},
// 设置请求头 xhr: 异步请求, formData: 表单对象
header: (xhr, formData) => {
// xhr.setRequestHeader('myHeader','myValue');
formData.append("imageType", this.formData.contentImage);
formData.append("tableType", this.formData.tableType);
formData.append("action", this.formData.action);
},
// start: function (){}
start: () => {}, // 可选参数 接收一个函数 开始上传数据时会触发
end: () => {}, // 可选参数 接收一个函数 上传数据完成(成功或者失败)时会触发
success: () => {}, // 可选参数 接收一个函数 上传数据成功时会触发
error: () => {} // 可选参数 接收一个函数 上传数据中断时会触发
},
// 以下所有设置都和vue-quill-editor本身所对应
modules: {
toolbar: [], //工具菜单栏配置
handlers: {
image: function(value) {
if (value) {
// 触发input框选择图片文件
document.querySelector(".avatar-uploader input").click();
} else {
this.quill.format("image", false);
}
},
video: function(val) {
document.querySelector("#upvideoshow").click();
}
}
},
placeholder: "请在这里添加描述", //提示
readyOnly: false, //是否只读
theme: "snow", //主题 snow/bubble
syntax: true //语法检测
});
this.editorOption.modules.history = {
delay: 1000,
maxStack: 50,
userOnly: false
};
this.editorOption.modules.imageDrop = true;
this.editorOption.modules.toolbar = {
container: "#toolbar"
};
this.editorOption.modules.imageResize = {
displayStyles: {
backgroundColor: "black",
border: "none",
color: "white"
},
modules: ["Resize", "DisplaySize", "Toolbar"]
};
// this.uploadData.tableType = this.formData.tableType;
this.uploadData = this.formData;
},
computed: {
editor() {
return this.$refs.myQuillEditor.quill;
}
},
watch: {
content(newVal, oldVal) {
if (newVal) {
this.content = newVal;
} else if (!newVal) {
this.content = "";
}
}
},
methods: {
onEditorReady(editor) {
// 准备编辑器
},
onEditorBlur() {}, // 失去焦点事件
onEditorFocus(val) {
// 富文本获得焦点时的事件
},
/**
* @description [onEditorChange 输入文本改变事件]
* @param {Object} editor 返回的编辑对象{html, text, quill}
* @return {null} [没有返回]
*/
onEditorChange(editor) {
// console.log(editor);
this.content = editor.html;
this.$emit("content", this.content);
}, // 内容改变事件
// 富文本图片上传前
beforeUpload() {
// 显示loading动画
this.quillUpdateImg = true;
},
uploadSuccess(e, res, file) {
// 获取富文本组件实例
let quill = this.editor;
let _self = this;
// 如果上传成功
if (res.response.status === 0) {
_self.addRange = _self.$refs.myQuillEditor.quill.getSelection();
let length = _self.$refs.myQuillEditor.quill.selection.savedRange.index;
// 插入图片 res为服务器返回的图片地址
quill.insertEmbed(
_self.addRange !== null ? _self.addRange.index : 0,
"image",
res.response.data.originalImagePath,
Quill.sources
);
// 调整光标到最后
quill.setSelection(length + 1);
} else {
this.$Message.error("图片插入失败");
}
// loading动画消失
this.quillUpdateImg = false;
},
// 富文本图片上传失败
uploadError() {
// loading动画消失
this.quillUpdateImg = false;
this.$message.error("图片插入失败");
},
// 图片上传成功回调 插入到编辑器中
upScuccess(e, file, fileList) {
this.fullscreenLoading = false;
let vm = this;
let url = "";
url = e.data.originalVideo;
if (url != null && url.length > 0) {
// 将文件上传后的URL地址插入到编辑器文本中
let value = url;
vm.addRange = vm.$refs.myQuillEditor.quill.getSelection();
value = value.indexOf("http") !== -1 ? value : "http:" + value;
vm.$refs.myQuillEditor.quill.insertEmbed(
vm.addRange !== null ? vm.addRange.index : 0,
vm.uploadType,
value,
Quill.sources
); // 调用编辑器的 insertEmbed 方法,插入URL
} else {
}
this.$refs["upload"].clearFiles(); // 插入成功后清除input的内容
},
// 点击视频ICON触发事件
videoHandler() {
// this.addRange = this.$refs.myQuillEditor.quill.getSelection();
// if (state) {
let fileInput = document.getElementById("imgInput");
fileInput.click(); // 加一个触发事件
// 加一个触发事件
// }
// this.uploadType = "video";
}
},
// 页面加载后执行 为编辑器的图片图标和视频图标绑定点击事件
mounted() {
Quill.register("formats/lineHeight", lineHeight, true);
}
};
</script>
<style lang="scss">
@import "Quilleditor";
</style>
Quilleditor.scss
#Quill {
.quill-editor .ql-size .ql-picker-options {
height: 200px;
overflow: auto;
}
.ql-container {
min-height: 350px;
font-size: 16px;
line-height: 1.4;
}
/** 设置行高 */
.ql-toolbar {
text-align: left;
}
.ql-lineHeight {
margin: 6px 0 0 0;
.ql-picker-options {
height: 200px;
overflow: auto;
}
}
.ql-lineHeight::before {
content: "行高:";
position: relative;
top: -2px;
left: 8px;
}
.ql-lineHeight .ql-picker-label {
left: 50px;
top: -25px;
}
.ql-lineHeight .ql-picker-options {
left: 50px;
}
.ql-picker.ql-lineHeight .ql-picker-label[data-value='1']::before,
.ql-picker.ql-lineHeight .ql-picker-item[data-value='1']::before {
content: "1.0";
}
.ql-picker.ql-lineHeight .ql-picker-label[data-value="1.1"]::before,
.ql-picker.ql-lineHeight .ql-picker-item[data-value="1.1"]::before {
content: "1.1";
}
.ql-picker.ql-lineHeight .ql-picker-label[data-value="1.2"]::before,
.ql-picker.ql-lineHeight .ql-picker-item[data-value="1.2"]::before {
content: "1.2";
}
.ql-picker.ql-lineHeight .ql-picker-label[data-value="1.3"]::before,
.ql-picker.ql-lineHeight .ql-picker-item[data-value="1.3"]::before {
content: "1.3";
}
.ql-picker.ql-lineHeight .ql-picker-label[data-value="1.4"]::before,
.ql-picker.ql-lineHeight .ql-picker-item[data-value="1.4"]::before {
content: "1.4";
}
.ql-picker.ql-lineHeight .ql-picker-label[data-value="1.5"]::before,
.ql-picker.ql-lineHeight .ql-picker-item[data-value="1.5"]::before {
content: "1.5";
}
.ql-picker.ql-lineHeight .ql-picker-label[data-value="1.6"]::before,
.ql-picker.ql-lineHeight .ql-picker-item[data-value="1.6"]::before {
content: "1.6";
}
.ql-picker.ql-lineHeight .ql-picker-label[data-value="1.7"]::before,
.ql-picker.ql-lineHeight .ql-picker-item[data-value="1.7"]::before {
content: "1.7";
}
.ql-picker.ql-lineHeight .ql-picker-label[data-value="1.8"]::before,
.ql-picker.ql-lineHeight .ql-picker-item[data-value="1.8"]::before {
content: "1.8";
}
.ql-picker.ql-lineHeight .ql-picker-label[data-value="1.9"]::before,
.ql-picker.ql-lineHeight .ql-picker-item[data-value="1.9"]::before {
content: "1.9";
}
.ql-picker.ql-lineHeight .ql-picker-label[data-value="2"]::before,
.ql-picker.ql-lineHeight .ql-picker-item[data-value="2"]::before {
content: "2.0";
}
.ql-picker.ql-lineHeight .ql-picker-label[data-value="2.1"]::before,
.ql-picker.ql-lineHeight .ql-picker-item[data-value="2.1"]::before {
content: "2.1";
}
.ql-picker.ql-lineHeight .ql-picker-label[data-value="2.2"]::before,
.ql-picker.ql-lineHeight .ql-picker-item[data-value="2.2"]::before {
content: "2.2";
}
.ql-picker.ql-lineHeight .ql-picker-label[data-value="2.3"]::before,
.ql-picker.ql-lineHeight .ql-picker-item[data-value="2.3"]::before {
content: "2.3";
}
.ql-picker.ql-lineHeight .ql-picker-label[data-value="2.4"]::before,
.ql-picker.ql-lineHeight .ql-picker-item[data-value="2.4"]::before {
content: "2.4";
}
.ql-picker.ql-lineHeight .ql-picker-label[data-value="2.5"]::before,
.ql-picker.ql-lineHeight .ql-picker-item[data-value="2.5"]::before {
content: "2.5";
}
.ql-picker.ql-lineHeight .ql-picker-label[data-value="2.6"]::before,
.ql-picker.ql-lineHeight .ql-picker-item[data-value="2.6"]::before {
content: "2.6";
}
.ql-picker.ql-lineHeight .ql-picker-label[data-value="2.7"]::before,
.ql-picker.ql-lineHeight .ql-picker-item[data-value="2.7"]::before {
content: "2.7";
}
.ql-picker.ql-lineHeight .ql-picker-label[data-value="2.8"]::before,
.ql-picker.ql-lineHeight .ql-picker-item[data-value="2.8"]::before {
content: "2.8";
}
.ql-picker.ql-lineHeight .ql-picker-label[data-value="2.9"]::before,
.ql-picker.ql-lineHeight .ql-picker-item[data-value="2.9"]::before {
content: "2.9";
}
.ql-picker.ql-lineHeight .ql-picker-label[data-value="3"]::before,
.ql-picker.ql-lineHeight .ql-picker-item[data-value="3"]::before {
content: "3.0";
}
.ql-editor {
max-height: 500px;
}
}
组件调用
<Quilleditor @content="onchangecontent" ref="Quilleditor">
</Quilleditor>
// 富文本内容
onchangecontent(event) {
this.formValidate.content = event;
}
lineHeight.js
import Quill from 'quill'
let Parchment = Quill.import('parchment');
class lineHeightAttributor extends Parchment.Attributor.Style {}
let lineHeight = new lineHeightAttributor('lineHeight', 'line-height', {
scope: Parchment.Scope.INLINE,
whitelist: ['1', '1.1','1.2','1.3','1.4','1.5','1.6','1.7','1.8','1.9','2','2.1','2.2','2.3','2.4','2.5','2.6','2.7','2.8','2.9','3']
});
Quill.register({ "formats/lineHeight": lineHeight }, true);
export default lineHeight;
调用图片放大缩小时要配置这个哦,不然会报错!
//vue.config.js
const webpack = require('webpack')
configureWebpack: {
plugins: [
new webpack.ProvidePlugin({
'window.Quill': 'quill/dist/quill.js',
'Quill': 'quill/dist/quill.js'
}),
]
},
//webpack.config
build: {
plugins: [
new webpack.ProvidePlugin({
'window.Quill': 'quill/dist/quill.js',
'Quill': 'quill/dist/quill.js'
})
]
},