|
@@ -0,0 +1,252 @@
|
|
|
|
+<template>
|
|
|
|
+ <div class="quillEditor">
|
|
|
|
+ <div style="min-height: 460px">
|
|
|
|
+ <quill-editor
|
|
|
|
+ ref="myQuillEditor"
|
|
|
|
+ v-model="content"
|
|
|
|
+ :options="editorOption"
|
|
|
|
+ @blur="onEditorBlur($event)"
|
|
|
|
+ @focus="onEditorFocus($event)"
|
|
|
|
+ @ready="onEditorReady($event)"
|
|
|
|
+ />
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+</template>
|
|
|
|
+
|
|
|
|
+<script>
|
|
|
|
+import "quill/dist/quill.core.css";
|
|
|
|
+import "quill/dist/quill.snow.css";
|
|
|
|
+import "quill/dist/quill.bubble.css";
|
|
|
|
+import { quillEditor, Quill } from "vue-quill-editor";
|
|
|
|
+import { uploadPic } from "@/api/upload";
|
|
|
|
+import { container, ImageExtend, QuillWatch } from "quill-image-extend-module";
|
|
|
|
+Quill.register('modules/ImageExtend', ImageExtend)
|
|
|
|
+
|
|
|
|
+const titleConfig = [
|
|
|
|
+ { 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: "两端对齐"
|
|
|
|
+ }
|
|
|
|
+];
|
|
|
|
+
|
|
|
|
+export default {
|
|
|
|
+ props: {
|
|
|
|
+ value: String
|
|
|
|
+ },
|
|
|
|
+ model: {
|
|
|
|
+ prop: "value",
|
|
|
|
+ event: "input"
|
|
|
|
+ },
|
|
|
|
+ data() {
|
|
|
|
+ return {
|
|
|
|
+ editorOption: {
|
|
|
|
+ modules: {
|
|
|
|
+ ImageExtend: {
|
|
|
|
+ // 如果不作设置,即{} 则依然开启复制粘贴功能且以base64插入
|
|
|
|
+ name: "file", // 图片参数名
|
|
|
|
+ size: 3, // 可选参数 图片大小,单位为M,1M = 1024kb
|
|
|
|
+ action: "/node-upload/uploadfile", // 服务器地址, 如果action为空,则采用base64插入图片
|
|
|
|
+ // response 为一个函数用来获取服务器返回的具体图片地址
|
|
|
|
+ // 例如服务器返回{code: 200; data:{ url: 'baidu.com'}}
|
|
|
|
+ // 则 return res.data.url
|
|
|
|
+ response: res => {
|
|
|
|
+ return res.data.url;
|
|
|
|
+ },
|
|
|
|
+ sizeError: () => {}, // 图片超过大小的回调
|
|
|
|
+ start: () => {}, // 可选参数 自定义开始上传触发事件
|
|
|
|
+ end: () => {}, // 可选参数 自定义上传结束触发的事件,无论成功或者失败
|
|
|
|
+ error: () => {}, // 可选参数 上传失败触发的事件
|
|
|
|
+ success: () => {}, // 可选参数 上传成功触发的事件
|
|
|
|
+ change: (xhr, formData) => {
|
|
|
|
+ // xhr.setRequestHeader('myHeader','myValue')
|
|
|
|
+ // formData.append('token', 'myToken')
|
|
|
|
+ } // 可选参数 每次选择图片触发,也可用来设置头部,但比headers多了一个参数,可设置formData
|
|
|
|
+ },
|
|
|
|
+
|
|
|
|
+ toolbar: {
|
|
|
|
+ // 如果不上传图片到服务器,此处不必配置
|
|
|
|
+ container: [
|
|
|
|
+ ["bold", "italic", "underline", "strike"], // toggled buttons
|
|
|
|
+ ["blockquote", "code-block"],
|
|
|
|
+
|
|
|
|
+ [{ header: 1 }, { header: 2 }], // custom button values
|
|
|
|
+ [{ list: "ordered" }, { list: "bullet" }],
|
|
|
|
+ [{ script: "sub" }, { script: "super" }], // superscript/subscript
|
|
|
|
+ [{ indent: "-1" }, { indent: "+1" }], // outdent/indent
|
|
|
|
+ [{ direction: "rtl" }], // text direction
|
|
|
|
+
|
|
|
|
+ [{ size: ["small", false, "large", "huge"] }], // custom dropdown
|
|
|
|
+ [{ header: [1, 2, 3, 4, 5, 6, false] }],
|
|
|
|
+
|
|
|
|
+ [{ color: [] }, { background: [] }], // dropdown with defaults from theme
|
|
|
|
+ [{ font: [] }],
|
|
|
|
+ [{ align: [] }],
|
|
|
|
+ ["image"] //去除video即可
|
|
|
|
+ ], // container为工具栏,此次引入了全部工具栏,也可自行配置
|
|
|
|
+ handlers: {
|
|
|
|
+ image: function() {
|
|
|
|
+ // 劫持原来的图片点击按钮事件
|
|
|
|
+ QuillWatch.emit(this.quill.id);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ };
|
|
|
|
+ },
|
|
|
|
+ computed: {
|
|
|
|
+ content: {
|
|
|
|
+ set(val) {
|
|
|
|
+ this.$emit("input", val);
|
|
|
|
+ },
|
|
|
|
+ get() {
|
|
|
|
+ return this.value;
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ editor() {
|
|
|
|
+ return this.$refs.myQuillEditor.quill;
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ components: {
|
|
|
|
+ quillEditor
|
|
|
|
+ },
|
|
|
|
+ methods: {
|
|
|
|
+ // onEditorInput (e) {
|
|
|
|
+ // this.$emit('input', e)
|
|
|
|
+ // },
|
|
|
|
+ onEditorBlur(quill) {
|
|
|
|
+ // console.log("editor blur!", quill);
|
|
|
|
+ },
|
|
|
|
+ onEditorFocus(quill) {
|
|
|
|
+ // console.log("editor focus!", quill);
|
|
|
|
+ },
|
|
|
|
+ onEditorReady(quill) {
|
|
|
|
+ // console.log("editor ready!", quill);
|
|
|
|
+ },
|
|
|
|
+ onEditorChange({ quill, html, text }) {
|
|
|
|
+ // console.log("editor change!", quill, html, text);
|
|
|
|
+ this.content = html;
|
|
|
|
+ },
|
|
|
|
+ autotip() {
|
|
|
|
+ document.getElementsByClassName("ql-editor")[0].dataset.placeholder = "";
|
|
|
|
+ for (let item of titleConfig) {
|
|
|
|
+ let tip = document.querySelector(".quill-editor " + item.Choice);
|
|
|
|
+ if (!tip) continue;
|
|
|
|
+ tip.setAttribute("title", item.title);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ mounted() {
|
|
|
|
+ console.log("this is current quill instance object", this.editor);
|
|
|
|
+ this.autotip();
|
|
|
|
+ this.editor.root.addEventListener(
|
|
|
|
+ "paste",
|
|
|
|
+ evt => {
|
|
|
|
+ if (
|
|
|
|
+ evt.clipboardData &&
|
|
|
|
+ evt.clipboardData.files &&
|
|
|
|
+ evt.clipboardData.files.length
|
|
|
|
+ ) {
|
|
|
|
+ evt.preventDefault();
|
|
|
|
+ [].forEach.call(evt.clipboardData.files, file => {
|
|
|
|
+ if (!file.type.match(/^image\/(gif|jpe?g|a?png|bmp)/i)) {
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ uploadPic(blob)(file, res => {
|
|
|
|
+ var range = this.editor.getSelection();
|
|
|
|
+ if (range) {
|
|
|
|
+ // 在当前光标位置插入图片
|
|
|
|
+ this.editor.insertEmbed(
|
|
|
|
+ range.index,
|
|
|
|
+ "image",
|
|
|
|
+ this.$ajax.defaults.baseURL + res.file.path
|
|
|
|
+ );
|
|
|
|
+ // 将光标移动到图片后面
|
|
|
|
+ this.editor.setSelection(range.index + 1);
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ false
|
|
|
|
+ );
|
|
|
|
+ }
|
|
|
|
+};
|
|
|
|
+</script>
|
|
|
|
+
|
|
|
|
+<style lang="less">
|
|
|
|
+.act-edit {
|
|
|
|
+ padding: 30px;
|
|
|
|
+ .ql-snow .ql-picker {
|
|
|
|
+ color: #fff;
|
|
|
|
+ }
|
|
|
|
+ .ql-snow .ql-stroke {
|
|
|
|
+ stroke: #fff;
|
|
|
|
+ }
|
|
|
|
+ .ql-snow .ql-fill,
|
|
|
|
+ .ql-snow .ql-stroke.ql-fill {
|
|
|
|
+ fill: #fff;
|
|
|
|
+ }
|
|
|
|
+ .ql-editor {
|
|
|
|
+ background: #161a1a;
|
|
|
|
+ min-height: 460px;
|
|
|
|
+ }
|
|
|
|
+ .ql-toolbar.ql-snow .ql-picker.ql-expanded .ql-picker-options {
|
|
|
|
+ color: #000;
|
|
|
|
+ }
|
|
|
|
+ .ql-snow .ql-icon-picker .ql-picker-item svg line {
|
|
|
|
+ stroke: #444;
|
|
|
|
+ }
|
|
|
|
+ .ql-snow .ql-picker-label::before {
|
|
|
|
+ vertical-align: top;
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+</style>
|