一、全局注冊: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' })
