123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523 |
- <template>
- <div>
- <!-- 图片上传组件辅助-->
- <el-upload
- class="avatar-uploader"
- action="notnull"
- :http-request="uploadFileFun"
- name="img"
- :headers="header"
- :show-file-list="false"
- :on-success="uploadSuccess"
- :on-error="uploadError"
- :before-upload="beforeUpload"
- v-show="false">
- <el-button class="stBtnUpload" size="small" type="primary">点击上传</el-button>
- </el-upload>
- <el-button style="display: none" @click="richtext()" size="small" type="primary">返回</el-button>
- <quill-editor
- class="editor"
- v-model="content"
- :ref="quillEditorRef"
- :options="editorOption"
- @blur="onEditorBlur($event)" @focus="onEditorFocus($event)"
- @change="onEditorChange($event)">
- </quill-editor>
- </div>
- </template>
- <script>
- let cusSpecial = ['α', 'β', 'γ'];
- // 工具栏配置
- const toolbarOptions = [
- ['bold', 'italic', 'underline', 'strike'], // 加粗 斜体 下划线 删除线
- ['blockquote', 'code-block', 'formula'], // 引用 代码块
- [{ header: 1 }, { header: 2 }], // 1、2 级标题
- [{ list: 'ordered' }, { list: 'bullet' }], // 有序、无序列表
- [{ script: 'sub' }, { script: 'super' }], // 上标/下标
- [{ indent: '-1' }, { indent: '+1' }], // 缩进
- // [{'direction': 'rtl'}], // 文本方向
- [{ size: ['small', false, 'large', 'huge'] }], // 字体大小
- [{ header: [1, 2, 3, 4, 5, 6, false] }], // 标题
- [{ color: [] }, { background: [] }], // 字体颜色、字体背景颜色
- [{ font: [] }], // 字体种类
- [{ align: [] }], // 对齐方式
- ['clean'], // 清除文本格式
- ['link', 'image', 'video'], // 链接、图片、视频
- cusSpecial, // 特殊符号
- ];
- import { quillEditor } from 'vue-quill-editor';
- import * as Quill from 'quill';
- import * as Delta from 'quill-delta';
- import ImageResize from 'quill-image-resize-module';
- import StImage from './QuillEditorStBlockEmbed';
- Quill.register('modules/imageResize', ImageResize);
- Quill.register('formats/stImage', StImage);
- import 'quill/dist/quill.core.css';
- import 'quill/dist/quill.snow.css';
- import 'quill/dist/quill.bubble.css';
- import { getUploadImg } from '@/api/AlCloud';
- import { getUploadConfig } from '@/api/base64';
- import axios from 'axios';
- import store from '@/store';
- export default {
- props: {
- /*编辑器的内容*/
- value: {
- type: String,
- },
- flg: {
- type: String,
- },
- quillEditorRef: {
- type: String,
- },
- /*图片大小*/
- maxSize: {
- type: Number,
- default: 4000, //kb
- },
- },
- components: {
- quillEditor,
- },
- data() {
- return {
- curLength: 0,
- uploadfileParam: {},
- content: this.value,
- quillUpdateImg: false, // 根据图片上传状态来确定是否显示loading动画,刚开始是false,不显示
- editorOption: {
- theme: 'snow', // or 'bubble'
- placeholder: '请输入内容...',
- modules: {
- toolbar: {
- container: toolbarOptions,
- handlers: {
- image: function (value) {
- if (value) {
- // 触发input框选择图片文件
- // this.$refs[this.btnRef].click();
- this.container.parentElement.parentElement.children[0].children[0].children[0].click();
- this.container.parentElement.parentElement.children[1].click();
- } else {
- this.quill.format('image', false);
- }
- },
- 'formula': (value) => {
- let quill = this.$refs[this.quillEditorRef].quill;
- this.curLength = quill.getSelection() ? quill.getSelection().index : 0;
- let chuck = this.getSelectionLatex();
- if (chuck) {
- this.formula.latex = chuck.latex;
- this.formula.type = chuck.type;
- } else {
- this.formula.latex = '';
- this.formula.type = '';
- }
- this.formula.dialogVisible = true;
- this.formula.quillEditorRef = this.quillEditorRef;
- store.commit({
- type: 'setFormula'
- , formula: this.formula,
- });
- },
- 'α': (value) => {
- let quill = this.$refs[this.quillEditorRef].quill;
- // 获取光标所在位置
- let length = quill.getSelection().index;
- // 插入图片 res.url为服务器返回的图片地址
- /*quill.insertEmbed(length, 'image', `${multipartParams.url}/${multipartParams.key}`);
- // 调整光标到最后
- quill.setSelection(length + 1);*/
- quill.insertText(length, 'α');
- quill.setSelection(length + 1);
- },
- 'β': (value) => {
- let quill = this.$refs[this.quillEditorRef].quill;
- // 获取光标所在位置
- let length = quill.getSelection().index;
- // 插入图片 res.url为服务器返回的图片地址
- /*quill.insertEmbed(length, 'image', `${multipartParams.url}/${multipartParams.key}`);
- // 调整光标到最后
- quill.setSelection(length + 1);*/
- quill.insertText(length, 'β');
- quill.setSelection(length + 1);
- },
- 'γ': (value) => {
- let quill = this.$refs[this.quillEditorRef].quill;
- // 获取光标所在位置
- let length = quill.getSelection().index;
- // 插入图片 res.url为服务器返回的图片地址
- /*quill.insertEmbed(length, 'image', `${multipartParams.url}/${multipartParams.key}`);
- // 调整光标到最后
- quill.setSelection(length + 1);*/
- quill.insertText(length, 'γ');
- quill.setSelection(length + 1);
- },
- },
- },
- imageResize: {},
- },
- },
- // serverUrl: "/v1/blog/imgUpload", // 这里写你要上传的图片服务器地址
- header: {
- // token: sessionStorage.token
- }, // 有的图片服务器要求请求头需要有token
- currentImgSrc: '',
- sttipinputw: 0,
- sttipinputh: 0,
- formula: {
- dialogVisible: false,
- imgsrc: '',
- latex: '',
- type: '',
- quillEditorRef: '',
- },
- };
- },
- methods: {
- // describe: 此功能用户放切屏点击图片失去焦点 author: Wgy date:2020-07-07
- richtext(){
- window.onblur = null;
- this.$emit('richText','richtext');
- },
- onEditorBlur() {
- //失去焦点事件
- },
- onEditorFocus() {
- //获得焦点事件
- },
- onEditorChange() {
- //内容改变事件
- this.$emit('syncValue', this.flg, this.content);
- },
- // 富文本图片上传前
- beforeUpload() {
- // 显示loading动画
- this.quillUpdateImg = true;
- },
- uploadSuccess(res, file) {
- },
- // 富文本图片上传失败
- uploadError() {
- // loading动画消失
- this.quillUpdateImg = false;
- },
- uploadFileFun(truck) {
- var file = truck.file;
- const suffix = file.name.split('.').pop();
- var dd = new Date();
- var y = dd.getFullYear();
- var m = dd.getMonth() + 1;//获取当前月份的日期
- const options = {
- prefix: 'resource/QuillEditor/' + y + m + '/',
- suffix: suffix,
- };
- getUploadImg(options).then((res) => {
- if (res.code === 0) {
- // 二进制文件通过forData对象进行传递
- const FormDataForAl = new FormData();
- const multipartParams = Object.assign({}, res.data, {
- Filename: `images/${file.name}`,
- success_action_status: '200',
- });
- // 参数数据
- FormDataForAl.append('key', multipartParams.key);
- FormDataForAl.append('policy', multipartParams.policy);
- FormDataForAl.append('signature', multipartParams.signature);
- FormDataForAl.append('OSSAccessKeyId', multipartParams.accessid);
- FormDataForAl.append('success_action_status', multipartParams.success_action_status);
- // OSS要求, file放到最后
- FormDataForAl.append('file', file);
- axios.post(multipartParams.uploadUrl, FormDataForAl).then(alRes => {
- if (alRes.status === 200) {
- let quill = this.$refs[this.quillEditorRef].quill;
- // 获取光标所在位置
- let length = quill.getSelection().index;
- // 插入图片 res.url为服务器返回的图片地址
- quill.insertEmbed(length, 'image', `${multipartParams.downloadUrl}/${multipartParams.key}`);
- // 调整光标到最后
- quill.setSelection(length + 1);
- }
- }).catch(alerr => {
- this.$message.error('图片插入失败');
- console.error('阿里云错误', alerr);
- });
- }
- });
- },
- clearContent() {
- this.content = '';
- },
- setContent(val) {
- this.content = val;
- },
- quillEditorAddEventListener() {
- let dom = this.$refs[this.quillEditorRef].$el.children[1].children[0];
- let quill = this.$refs[this.quillEditorRef].quill;
- let that = this;
- var pasteFun = function (e) {
- var clipboardData = e.clipboardData;
- if (!(clipboardData && clipboardData.items)) {//是否有粘贴内容
- return;
- }
- for (var i = 0; i < clipboardData.items.length; i++) {
- var item = clipboardData.items[i];
- if (item.kind === 'string' && item.type === 'text/plain') {
- item.getAsString((str) => {
- // str 是获取到的字符串,创建文本框
- //处理粘贴的文字内容
- setTimeout(() => {
- let length = quill.getSelection().index;
- // 插入
- quill.insertText(length, str);
- // 调整光标到最后
- quill.setSelection(length + str.length);
- }, 50);
- });
- } else if (item.kind === 'file') {//file 一般是各种截图base64数据
- var pasteFile = item.getAsFile();
- // pasteFile就是获取到的文件
- var reader = new FileReader();
- reader.onload = function (event) {
- var base64Img = event.target.result;
- // image/png;base64,
- let base64ImgPrefix = base64Img.substring(0, base64Img.indexOf(',') + 1);
- let base64ImgData = base64Img.substring(base64Img.indexOf(',') + 1);
- let opt = {
- 'data': base64ImgData,
- 'prefix': 'resource/',
- 'suffix': base64ImgPrefix.substring(base64ImgPrefix.indexOf('/') + 1, base64ImgPrefix.indexOf(';')),
- };
- getUploadConfig(opt).then(res => {
- if (res.code === 0) {
- let uri = res.data;
- // 获取光标所在位置
- let length = quill.getSelection().index;
- // 插入图片 res.url为服务器返回的图片地址
- quill.insertEmbed(length, 'image', uri);
- // 调整光标到最后
- quill.setSelection(length + 1);
- } else {
- that.$message.error('图片插入失败');
- }
- });
- }; // data url
- reader.readAsDataURL(pasteFile);
- }
- }
- };
- dom.removeEventListener('paste', pasteFun);
- dom.addEventListener('paste', pasteFun);
- },
- getSelectionLatex() {
- let type = '';
- let leaf = null;
- // 如果光标前一个是公式 取得公式的latex
- let quill = this.$refs[this.quillEditorRef].quill;
- let selection = quill.getSelection();
- if (!selection) {
- return null;
- }
- if (selection.length === 0) {
- type = 'rightSingle';
- leaf = quill.getLeaf(selection.index);
- } else {
- type = 'selected';
- leaf = quill.getLeaf(selection.index + 1);
- }
- // let contents = quill.getContents();
- // let line = quill.getLine(selection.index);
- // let bounds = quill.getBounds(selection.index);
- // console.log(selection, leaf);
- if (leaf[0] instanceof StImage) {
- // console.log(leaf[0].domNode.dataset.latex);
- return {
- type: type,
- latex: leaf[0].domNode.dataset.latex,
- };
- }
- return null;
- },
- // Delta operation
- delQuillContent(index) {
- let quill = this.$refs[this.quillEditorRef].quill;
- /*console.dir(quill);
- console.dir(quill.getSelection());
- console.dir(quill.getContents());*/
- // .insert('White', { color: '#fff' })
- var stDelta = new Delta().retain(index).delete(1);
- let quillContents = quill.getContents().compose(stDelta);
- quill.setContents(quillContents);
- },
- passValue() {
- // console.log('do passValue!!');
- let latex = this.formula.latex;
- if (latex.indexOf('placeholder') > -1) {
- this.formula.dialogVisible = false;
- let quill = this.$refs[this.quillEditorRef].quill;
- quill.setSelection(this.curLength);
- return;
- }
- if (latex && latex !== '') {
- if (this.formula.type === 'rightSingle') {
- // del formula
- this.delQuillContent(this.curLength - 1);
- let quill = this.$refs[this.quillEditorRef].quill;
- // 获取光标所在位置
- // let length = quill.getSelection() ? quill.getSelection().index : 0;
- // 插入图片 res.url为服务器返回的图片地址
- quill.insertEmbed(this.curLength - 1, 'stimage', {
- src: this.formula.imgsrc,
- 'data-latex': latex,
- });
- // quill.formatText(length, 1, { 'data-latex': latex });
- /*var delta = quill.getContents();
- console.log(delta);*/
- // 调整光标到最后
- // quill.insertText(length, img);
- quill.setSelection(this.curLength);
- } else if (this.formula.type === 'selected') {
- // del formula
- this.delQuillContent(this.curLength);
- let quill = this.$refs[this.quillEditorRef].quill;
- // 获取光标所在位置
- // let length = quill.getSelection() ? quill.getSelection().index : 0;
- // 插入图片 res.url为服务器返回的图片地址
- quill.insertEmbed(this.curLength, 'stimage', {
- src: this.formula.imgsrc,
- 'data-latex': latex,
- });
- // quill.formatText(length, 1, { 'data-latex': latex });
- /*var delta = quill.getContents();
- console.log(delta);*/
- // 调整光标到最后
- // quill.insertText(length, img);
- quill.setSelection(this.curLength + 1);
- } else {
- let quill = this.$refs[this.quillEditorRef].quill;
- // 获取光标所在位置
- // let length = quill.getSelection() ? quill.getSelection().index : 0;
- // 插入图片 res.url为服务器返回的图片地址
- quill.insertEmbed(this.curLength, 'stimage', {
- src: this.formula.imgsrc,
- 'data-latex': latex,
- });
- // quill.formatText(length, 1, { 'data-latex': latex });
- /*var delta = quill.getContents();
- console.log(delta);*/
- // 调整光标到最后
- // quill.insertText(length, img);
- quill.setSelection(this.curLength + 1);
- this.formula.dialogVisible = false;
- }
- this.formula.dialogVisible = false;
- }
- },
- },
- mounted() {
- let checkCount = 0;
- let checkCountMax = 100;
- let stInterval = setInterval(() => {
- if (this.quillEditorRef) {
- clearInterval(stInterval);
- this.$nextTick(function () {
- this.quillEditorAddEventListener();
- });
- /*let dom = this.$refs[this.quillEditorRef].$el.children[1].children[0];
- const specialSignals = document.querySelectorAll('.ql-special-signal');
- for (const specialSignal of specialSignals) {
- // specialSignal.style.cssText = "width:80px; border:1px solid #ccc; border-radius:5px;";
- // specialSignal.style.cssText = "width:50px;";
- // specialSignal.innerText="特殊符号";
- specialSignal.classList.add('el-icon-edit-outline');
- specialSignal.title = "特殊符号";
- }*/
- for (const special of cusSpecial) {
- const specialSignals = document.querySelectorAll('.ql-' + special);
- for (const specialSignal of specialSignals) {
- // specialSignal.style.cssText = "width:80px; border:1px solid #ccc; border-radius:5px;";
- // specialSignal.style.cssText = "width:50px;";
- specialSignal.innerText = special;
- // specialSignal.classList.add('el-icon-edit-outline');
- specialSignal.title = special;
- }
- }
- } else {
- if (checkCount > checkCountMax) {
- clearInterval(stInterval);
- }
- }
- checkCount++;
- }, 100);
- /*监听富文本复制粘贴*/
- document.onpaste = function (e) {
- let arrPath = e.path;
- let has = false;
- if (arrPath) {
- for (const path of arrPath) {
- if (path.className && path.className.indexOf('ql-editor') > -1) {
- has = true;
- break;
- }
- }
- }
- if (has) {
- e.preventDefault();
- }
- };
- },
- watch: {
- '$store.state.formula': {
- handler(newVal, oldVal) {
- // console.log('in store.state.formula');
- // console.log(newVal);
- this.formula = newVal;
- /*console.dir('======start=======');
- console.dir(this.formula.quillEditorRef);
- console.dir(this.quillEditorRef);
- console.dir('======end=======');*/
- if (this.formula.dialogVisible === false && this.formula.quillEditorRef === this.quillEditorRef) {
- this.passValue();
- }
- },
- deep: true,
- },
- },
- };
- </script>
|