<template>
|
<div class="edit_container">
|
<quill-editor
|
v-model="content"
|
class="myQuillEditor"
|
ref="myQuillEditor"
|
:options="editorOption"
|
@blur="onEditorBlur($event)"
|
@focus="onEditorFocus($event)"
|
@change="onEditorChange($event)"
|
></quill-editor>
|
<!-- 附件上传 -->
|
<el-upload
|
class="upload-demo"
|
:action="uploadUrl"
|
:headers="headers"
|
:on-success="handleSuccess"
|
multiple
|
:limit="1"
|
ref="upload"
|
:file-list="fileList"
|
accept=".pdf"
|
>
|
<el-button
|
size="small"
|
type="primary"
|
class="my-upload"
|
v-show="false"
|
style="height:0px"
|
>点击上传</el-button
|
>
|
<div slot="tip" class="el-upload__tip" style="margin-top:0px">
|
已选择附件:
|
</div>
|
</el-upload>
|
</div>
|
</template>
|
|
<script>
|
import { quillEditor } from "vue-quill-editor";
|
import Quill from "quill";
|
|
import "quill/dist/quill.core.css";
|
import "./quill.snow.css";
|
// import "quill/dist/quill.snow.css";
|
import "quill/dist/quill.bubble.css";
|
// import pdfjsLib from "pdfjs-dist";
|
|
import * as pdfjsLib from "pdfjs-dist";
|
import * as pdfjsWorker from "pdfjs-dist/build/pdf.worker.entry";
|
|
pdfjsLib.GlobalWorkerOptions.workerSrc = pdfjsWorker;
|
|
// import * as Quill from '../utils/quill';
|
|
// // import imageResize from "quill-image-resize-module";
|
// import { ImageDrop } from "quill-image-drop-module";
|
// Quill.register("modules/imageDrop", ImageDrop);
|
// Quill.register("modules/imageResize", imageResize);
|
|
// 源码中是import直接倒入,这里要用Quill.import引入
|
const Link = Quill.import("formats/link");
|
// 自定义a链接
|
class FileBlot extends Link {
|
// 继承Link Blot
|
static create(value) {
|
let node;
|
if (value && !value.href) {
|
// 适应原本的Link Blot
|
node = super.create(value);
|
} else {
|
// 自定义Link Blot
|
node = super.create(value.href);
|
node.href = value.href;
|
node.innerText = value.innerText;
|
// node.setAttribute('download', value.innerText); // 左键点击即下载
|
}
|
return node;
|
}
|
}
|
FileBlot.blotName = "link"; // 这里不用改,如果需要也可以保留原来的,这里用个新的blot
|
FileBlot.tagName = "A";
|
Quill.register(FileBlot); // 注册link
|
|
//设置字体大小
|
let fontSizeStyle = Quill.import("attributors/style/size"); //引入这个后会把样式写在style上
|
fontSizeStyle.whitelist = [
|
"12px",
|
"14px",
|
"16px",
|
"18px",
|
"20px",
|
"22px",
|
"24px",
|
"28px",
|
"32px",
|
"36px"
|
];
|
Quill.register(fontSizeStyle, true);
|
|
//设置光标位置
|
const bindings = {
|
custom: {
|
key: 13,
|
handler: function(range, context) {
|
this.quill.insertText(range.index, "\n ");
|
setTimeout(() => {
|
let nowRange = this.quill.getSelection().index - 1;
|
this.quill.setSelection(nowRange);
|
});
|
}
|
}
|
};
|
export default {
|
// name: "myEditor",
|
components: { quillEditor },
|
props: ["contentText"],
|
data() {
|
// 工具栏配置
|
const toolbarOptions = [
|
["bold", "italic", "underline", "strike"], //加粗,斜体,下划线,删除线
|
["blockquote", "code-block"], //引用,代码块
|
[{ header: 1 }, { header: 2 }], // 标题,键值对的形式;1、2表示字体大小
|
[{ list: "ordered" }, { list: "bullet" }], //列表
|
[{ script: "sub" }, { script: "super" }], // 上下标
|
[{ indent: "-1" }, { indent: "+1" }], // 缩进
|
[{ direction: "rtl" }], // 文本方向
|
[
|
{
|
size: [
|
"12px",
|
"14px",
|
"16px",
|
"18px",
|
"20px",
|
"22px",
|
"24px",
|
"28px",
|
"32px",
|
"36px"
|
]
|
}
|
], // 字体大小
|
[{ header: [1, 2, 3, 4, 5, 6, false] }], //几级标题
|
[{ color: [] }, { background: [] }], // 字体颜色,字体背景颜色
|
[{ font: [] }], //字体
|
[{ align: [] }], //对齐方式
|
["clean"], //清除字体样式
|
["link", "image", "upload"] // 链接、图片、视频
|
// ['sourceEditor']
|
];
|
const uploadConfig = {
|
action: this.$js.api.http + "communitypartybuilding/uploadimage", // 必填参数 图片上传地址
|
methods: "POST", // 必填参数 图片上传方式
|
token: "Bearer " + demo.$session.get("token") || "", // 可选参数 如果需要token验证,假设你的token有存放在sessionStorage
|
name: "file", // 必填参数 文件的参数名
|
size: 500, // 可选参数 图片大小,单位为Kb, 1M = 1024Kb
|
accept: "image/png, image/gif, image/jpeg, image/bmp, image/x-icon" // 可选 可上传的图片格式
|
};
|
|
return {
|
content: ``, // 富文本编辑器默认内容
|
// 富文本编辑器配置
|
editorOption: {
|
modules: {
|
toolbar: {
|
container: toolbarOptions,
|
handlers: {
|
upload: function() {
|
// 添加工具方法
|
document.querySelector(".upload-demo input").click();
|
},
|
image: function image() {
|
let self = this;
|
// let quill = this.$refs.myQuillEditor.quill;
|
|
var fileInput = this.container.querySelector(
|
"input.ql-image[type=file]"
|
);
|
if (fileInput === null) {
|
fileInput = document.createElement("input");
|
fileInput.setAttribute("type", "file");
|
// 设置图片参数名
|
if (uploadConfig.name) {
|
fileInput.setAttribute("name", uploadConfig.name);
|
}
|
// 可设置上传图片的格式
|
fileInput.setAttribute("accept", uploadConfig.accept);
|
fileInput.classList.add("ql-image");
|
// 监听选择文件
|
fileInput.addEventListener("change", function() {
|
// 创建formData
|
var formData = new FormData();
|
formData.append(uploadConfig.name, fileInput.files[0]);
|
// formData.append("object", "product");
|
// 如果需要token且存在token
|
if (uploadConfig.token) {
|
// formData.append("Authorization", uploadConfig.token);
|
// Authorization: "Bearer " + demo.$session.get("token") || ""
|
}
|
// 图片上传
|
var xhr = new XMLHttpRequest();
|
xhr.open(uploadConfig.methods, uploadConfig.action, true);
|
xhr.setRequestHeader(
|
"Authorization",
|
"Bearer " + demo.$session.get("token") || ""
|
);
|
// 上传数据成功,会触发
|
xhr.onload = function(e) {
|
if (xhr.status === 200) {
|
// let quill = self.$refs.myQuillEditor.quill;
|
|
var res = JSON.parse(xhr.responseText);
|
let length = self.quill.getSelection(true).index;
|
//这里很重要,你图片上传成功后,img的src需要在这里添加,res.path就是你服务器返回的图片链接。
|
|
self.quill.insertEmbed(length, "image", res.data);
|
self.quill.setSelection(length + 1);
|
}
|
fileInput.value = "";
|
};
|
// 开始上传数据
|
xhr.upload.onloadstart = function(e) {
|
fileInput.value = "";
|
};
|
// 当发生网络异常的时候会触发,如果上传数据的过程还未结束
|
xhr.upload.onerror = function(e) {};
|
// 上传数据完成(成功或者失败)时会触发
|
xhr.upload.onloadend = function(e) {
|
// console.log('上传结束')
|
};
|
xhr.send(formData);
|
});
|
this.container.appendChild(fileInput);
|
}
|
fileInput.click();
|
}
|
}
|
}, // 自定义工具栏,与上面定义的toolbarOptions 相对应
|
keyboard: {
|
bindings
|
}
|
},
|
theme: "snow", //主题
|
placeholder: "请输入正文"
|
},
|
headers: {
|
Authorization: "",
|
Token: ""
|
},
|
uploadUrl: this.$js.api.files,
|
fileList: [],
|
imageList: [],
|
loading: false
|
};
|
},
|
watch: {
|
contentText(newval) {
|
this.content = newval;
|
}
|
},
|
methods: {
|
// 失去焦点事件
|
onEditorBlur(editor) {
|
// console.log("editor blur!", editor);
|
},
|
// 获得焦点事件
|
onEditorFocus(editor) {
|
// console.log("editor focus!", editor);
|
},
|
// 内容改变事件
|
onEditorChange({ quill, html, text }) {
|
this.content = html;
|
this.$emit("editorContext", this.content);
|
},
|
//添加中文注释
|
addAnnotation() {
|
// toolbar标题
|
const titleConfig = [
|
{ Choice: ".ql-insertMetric", title: "跳转配置" },
|
{ Choice: ".ql-bold", title: "加粗" },
|
{ Choice: ".ql-italic", title: "斜体" },
|
{ Choice: ".ql-underline", title: "下划线" },
|
{ Choice: ".ql-header", title: "段落格式" },
|
{ Choice: ".ql-strike", title: "删除线" },
|
{ Choice: ".ql-blockquote", title: "块引用" },
|
{ Choice: ".ql-code", title: "插入代码" },
|
{ Choice: ".ql-code-block", title: "插入代码段" },
|
{ Choice: ".ql-font", title: "字体" },
|
{ Choice: ".ql-size", title: "字体大小" },
|
{ Choice: '.ql-list[value="ordered"]', title: "编号列表" },
|
{ Choice: '.ql-list[value="bullet"]', title: "项目列表" },
|
{ Choice: ".ql-direction", title: "文本方向" },
|
{ Choice: '.ql-header[value="1"]', title: "h1" },
|
{ Choice: '.ql-header[value="2"]', title: "h2" },
|
{ 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-formula", title: "插入公式" },
|
{ Choice: ".ql-clean", title: "清除字体格式" },
|
{ Choice: '.ql-script[value="sub"]', title: "下标" },
|
{ Choice: '.ql-script[value="super"]', title: "上标" },
|
{ Choice: '.ql-indent[value="-1"]', title: "向左缩进" },
|
{ Choice: '.ql-indent[value="+1"]', title: "向右缩进" },
|
{ Choice: ".ql-header .ql-picker-label", title: "标题大小" },
|
{
|
Choice: '.ql-header .ql-picker-item[data-value="1"]',
|
title: "标题一"
|
},
|
{
|
Choice: '.ql-header .ql-picker-item[data-value="2"]',
|
title: "标题二"
|
},
|
{
|
Choice: '.ql-header .ql-picker-item[data-value="3"]',
|
title: "标题三"
|
},
|
{
|
Choice: '.ql-header .ql-picker-item[data-value="4"]',
|
title: "标题四"
|
},
|
{
|
Choice: '.ql-header .ql-picker-item[data-value="5"]',
|
title: "标题五"
|
},
|
{
|
Choice: '.ql-header .ql-picker-item[data-value="6"]',
|
title: "标题六"
|
},
|
{ Choice: ".ql-header .ql-picker-item:last-child", title: "标准" },
|
{
|
Choice: '.ql-size .ql-picker-item[data-value="small"]',
|
title: "小号"
|
},
|
{
|
Choice: '.ql-size .ql-picker-item[data-value="large"]',
|
title: "大号"
|
},
|
{
|
Choice: '.ql-size .ql-picker-item[data-value="huge"]',
|
title: "超大号"
|
},
|
{ Choice: ".ql-size .ql-picker-item:nth-child(2)", title: "标准" },
|
{ Choice: ".ql-align .ql-picker-item:first-child", title: "居左对齐" },
|
{
|
Choice: '.ql-align .ql-picker-item[data-value="center"]',
|
title: "居中对齐"
|
},
|
{
|
Choice: '.ql-align .ql-picker-item[data-value="right"]',
|
title: "居右对齐"
|
},
|
{
|
Choice: '.ql-align .ql-picker-item[data-value="justify"]',
|
title: "两端对齐"
|
},
|
{ Choice: ".ql-upload", title: "上传文件" }
|
];
|
for (let item of titleConfig) {
|
let tip = document.querySelector(".quill-editor " + item.Choice);
|
if (!tip) continue;
|
tip.setAttribute("title", item.title);
|
}
|
},
|
//上传连接
|
async onUploadHandler(e) {
|
const imageUrl = e.target.value;
|
// 获取光标所在位置
|
let quill = this.$refs.myQuillEditor.quill;
|
let length = quill.getSelection().index;
|
// 插入图片
|
quill.insertEmbed(length, "image", imageUrl);
|
// 调整光标到最后
|
quill.setSelection(length + 1);
|
// this.content += url
|
},
|
//文件上传成功
|
handleSuccess(res, file) {
|
this.loadPDF(res.data);
|
},
|
handleBeforeUpload() {},
|
// 自定义按钮内容初始化
|
initButton() {
|
const editorButton = document.querySelector(".ql-upload");
|
editorButton.innerHTML =
|
'<i class="el-icon-upload" style="font-size: 18px;color:black"></i>';
|
},
|
async loadPDF(url) {
|
let load = demo.loading();
|
|
// 定义函数,将pdf转成图片
|
const pdf = await pdfjsLib.getDocument(url).promise;
|
const canvas = document.createElement("canvas");
|
const context = canvas.getContext("2d");
|
this.imageList = [];
|
// 循环遍历每一页pdf,将其转成图片
|
for (let i = 1; i <= pdf._pdfInfo.numPages; i++) {
|
// 获取pdf页
|
const page = await pdf.getPage(i);
|
|
// 获取页的尺寸
|
const viewport = page.getViewport({ scale: 1 });
|
|
// 设置canvas的尺寸
|
canvas.width = viewport.width;
|
canvas.height = viewport.height;
|
|
// 将pdf页渲染到canvas上
|
await page.render({ canvasContext: context, viewport: viewport })
|
.promise;
|
|
const image = canvas.toDataURL("image/jpeg");
|
console.log(image);
|
this.imageList.push({ image: image });
|
console.log(this.imageList);
|
}
|
|
// 获取光标所在位置
|
let quill = this.$refs.myQuillEditor.quill;
|
|
//多图上传
|
let uploadUrl = this.$js.api.http + "communitypartybuilding/uploads";
|
let formData = new FormData();
|
for (let index = 0; index < this.imageList.length; index++) {
|
const element = this.imageList[index];
|
const timer = new Date().getTime();
|
const urldata = this.dataURLtoFile(element.image, timer + ".png");
|
formData.append("files", urldata);
|
}
|
|
axios
|
.post(uploadUrl, formData, {
|
// 上传图片接口
|
headers: {
|
"Content-Type": "multipart/form-data",
|
Authorization: "Bearer " + demo.$session.get("token") || ""
|
}
|
})
|
.then(da => {
|
console.log(da);
|
if (da.data.code == 200) {
|
let imgUrl = da.data.data;
|
console.log(imgUrl);
|
imgUrl.map(item => {
|
//把图片插入编辑器
|
let length = quill.getSelection().index;
|
// 插入连接 res为连接地址
|
quill.insertEmbed(length, "image", item.url);
|
// quill.insertText(length, res.data);
|
quill.setSelection(length + 1);
|
});
|
demo.remove(load);
|
} else {
|
demo.remove(load);
|
demo.toast(da.data.data.msg);
|
return;
|
}
|
});
|
|
// this.$api.post("communitypartybuilding/uploadimage", formData, e => {
|
// console.log(e);
|
// });
|
|
// for (var i = 0; i < files.length; i++) {
|
// formData.append("files", files[i], files[i].name);
|
// }
|
},
|
dataURLtoFile(dataurl, filename) {
|
var arr = dataurl.split(","),
|
mime = arr[0].match(/:(.*?);/)[1],
|
bstr = atob(arr[1]),
|
n = bstr.length,
|
u8arr = new Uint8Array(n);
|
while (n--) {
|
u8arr[n] = bstr.charCodeAt(n);
|
}
|
return new File([u8arr], filename, { type: mime });
|
}
|
},
|
|
computed: {
|
editor() {
|
return this.$refs.myQuillEditor.quill;
|
}
|
},
|
mounted() {
|
this.headers = {
|
Authorization: "Bearer " + demo.$session.get("token") || ""
|
};
|
|
this.$nextTick(() => {
|
this.initButton();
|
this.addAnnotation();
|
});
|
}
|
};
|
</script>
|
|
<style>
|
.ql-snow .ql-tooltip[data-mode="link"]::before {
|
content: "请输入链接地址:";
|
}
|
.ql-snow .ql-tooltip.ql-editing a.ql-action::after {
|
border-right: 0px;
|
content: "保存";
|
padding-right: 0px;
|
}
|
.ql-snow .ql-tooltip[data-mode="video"]::before {
|
content: "请输入视频地址:";
|
}
|
.ql-snow .ql-picker.ql-size .ql-picker-label::before,
|
.ql-snow .ql-picker.ql-size .ql-picker-item::before {
|
content: "14px"; /*no*/
|
}
|
|
.ql-snow .ql-picker.ql-header .ql-picker-label::before,
|
.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-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-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="serif"]::before,
|
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="serif"]::before {
|
content: "衬线字体";
|
}
|
.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: "等宽字体";
|
}
|
.ql-editor {
|
min-height: 150px;
|
}
|
.ql-snow.ql-toolbar .ql-upload {
|
display: flex;
|
justify-content: center;
|
align-items: center;
|
}
|
</style>
|