一、全局注冊:main.js
import Vue from 'vue' import VueQuillEditor, { Quill } from 'vue-quill-editor' import { ImageDrop } from 'quill-image-drop-module' import ImageResize from 'quill-image-resize-module' import 'quill/dist/quill.core.css' import 'quill/dist/quill.snow.css' import 'quill/dist/quill.bubble.css' Quill.register('modules/imageDrop', ImageDrop) Quill.register('modules/imageResize', ImageResize) Vue.use(VueQuillEditor)
二、在組件中使用editor.vue
<template> <div class="editor"> <h3 class="otitle">寫文章</h3> <!-- 編輯器 --> <div class="editor_box"> <quill-editor v-model="content" ref="myQuillEditor" :options="editorOption" @blur="onEditorBlur($event)" @focus="onEditorFocus($event)" @ready="onEditorReady($event)"> </quill-editor> </div> <!-- 保存 --> <div class="save_box"> <el-button type="primary" @click="save()" size="mini">保存</el-button> </div> <!-- 文件上傳組件 --> <input type="file" value="" name="image" accept="image/*" @change="uploadImg" ref="uploadInput" class="uploadInput" /> </div> </template> <script> import { createAPI, addAccessToken, createImgSrc } from '@/utils/request' import qs from 'qs' import { unloadImg } from '@/utils/qiniu_unload' // 編輯器的參數配置 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: ['small', false, 'large', 'huge'] }], // 字體大小 [{ header: [1, 2, 3, 4, 5, 6, false] }], // 標題 [{ color: [] } // { background: [] } ], // 字體顏色、字體背景顏色 [{ font: [] }], // 字體種類 [{ align: [] }], // 對齊方式 ['clean'], // 清除文本格式 ['link', 'image' // 'video' ] // 鏈接、圖片、視頻 ] let iniCont = '' let myvue = { name: '', data () { return { content: iniCont, // 編輯器內容 // 工具欄配置 editorOption: { theme: 'snow', // 主題 placeholder: '您想說點什么?', modules: { toolbar: { container: toolbarOptions, // container: "#toolbar",//也可直接指向元素 handlers: { image: function (value) { if (value) { document.querySelector('.uploadInput').click() } else { this.quill.format('image', false) } } // link: function(value) { // if (value) { // var href = prompt('請輸入url'); // this.quill.format("link", href); // } else { // this.quill.format("link", false); // } // }, } }, imageResize: { //設置圖片大小 displayStyles: { backgroundColor: 'black', border: 'none', color: 'white' }, modules: [ 'Resize', 'DisplaySize', 'Toolbar' ] } } }, header: { // token: sessionStorage.token } } }, computed: {}, mounted () {}, methods: { // 保存 save () { }, // 失去焦點 onEditorBlur (quill) { // console.log('editor blur!', quill) }, // 獲得焦點 onEditorFocus (quill) { // console.log('editor focus!', quill) }, // 編輯器已准備完成 onEditorReady (quill) { // console.log('editor ready!', quill) }, // 關閉彈窗 close () { this.$refs.uploadInput.value = '' this.$store.commit('changeDialog', false) }, // 獲取裁剪后的圖片 getCropBlob () { let that = this that.$refs.cropper.getCropBlob((data) => { let _this = this unloadImg(data, function (res) {//上傳圖片 // 獲取富文本組件實例 let quill = _this.$refs.myQuillEditor.quill // 獲取光標所在位置 let length = quill.getSelection().index // 插入圖片 res.url為服務器返回的圖片地址 quill.insertEmbed(length, 'image', createImgSrc(res.res)) // 調整光標到最后 quill.setSelection(length + 1) }, function (res) { this.$message.error(res.res) }) that.close() }) } }, created () { } } export default myvue </script> <style> /* 漢化 */ .ql-container.ql-snow::-webkit-scrollbar { display: none; } .ql-editor::-webkit-scrollbar{ display: none; } .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'; } .ql-snow .ql-picker.ql-size .ql-picker-label[data-value=small]::before, .ql-snow .ql-picker.ql-size .ql-picker-item[data-value=small]::before { content: '10px'; } .ql-snow .ql-picker.ql-size .ql-picker-label[data-value=large]::before, .ql-snow .ql-picker.ql-size .ql-picker-item[data-value=large]::before { content: '18px'; } .ql-snow .ql-picker.ql-size .ql-picker-label[data-value=huge]::before, .ql-snow .ql-picker.ql-size .ql-picker-item[data-value=huge]::before { content: '32px'; } .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: '等寬字體'; } </style> <style lang='scss' > @import './editor.scss'; </style>
以上流程是由<input type="file" value="" name="image" accept="image/*" @change="uploadImg" ref="uploadInput" class="uploadInput" />獲取文件對象,然后將文件對象傳至事先封裝好的unloadImg方法中,如果上傳成功,則回調方法中返回圖片的key,再將拼接的圖片插入vue-quill-editor的光標處。
三、qiniu_unload.js將圖片上傳至七牛
import {createAPI, addAccessToken} from '@/utils/request' import storeLocal from 'store' // import qs from 'qs' let uploadToken = storeLocal.get('imgtoken') || 'abcdefg'// 從本地獲取圖片上傳憑證 let imgcache = '' let f1cache = '' let f2cache = '' // 上傳圖片 function unloadImg (data, f1, f2, boot) { imgcache = data f1cache = f1 f2cache = f2 const formdata = new FormData() formdata.append('file', data) formdata.append('key', 'img_' + new Date().getTime()) // 文件名 formdata.append('token', uploadToken) addAccessToken('no_check')// 由於七牛雲token失效返回401與本地后台token失效code碼一致,因此在此處傳值申明不驗證本地登錄 .post('http://upload-z2.qiniup.com/', formdata, { validateStatus: status => status === 200 }) .then(reponse => { let obj = { type: true, res: reponse.data.key } f1(obj)// 成功回調 }) .catch((response) => { if (boot) { // 攔截,防止死循環 let obj = { type: false, res: response.data.error } f2(obj)// 失敗回調 } if (response.status === 401) { // 上傳的圖片token失效 getTokenAgain()// 獲取新的token } }) } // 重新請求token function getTokenAgain () { addAccessToken() .post(createAPI('files/get_token'), '', { validateStatus: status => status === 200 }) .then(reponse => { uploadToken = reponse.data.data.unload_token storeLocal.set('imgtoken', uploadToken) unloadImg(imgcache, f1cache, f2cache, 1) }) .catch((response) => { return false }) } export { unloadImg }
結果展示:
裁剪工具用的vue-cropper,本文不做詳細介紹。
注意事項
1、vue-quill-editor插件quill-image-resize-module 報錯解決方法
解決方式就是修改wabpack配置
webpack.dev.conf.js
webpack.prod.conf.js 添加上即可解決問題,webpack.dev.conf.js是解決本地運行的問題,webpack.dev.conf.js是解決打包運行出錯。
new webpack.ProvidePlugin({ 'window.Quill': 'quill/dist/quill.js', 'Quill': 'quill/dist/quill.js' })