一、全局注册: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,本文不做详细介绍。
其他链接:php接入七牛云api、在七牛云建对象存储用于上传图片
注意事项
1、vue-quill-editor插件quill-image-resize-module 报错解决方法
解决方式就是修改wabpack配置
webpack.dev.conf.js
webpack.prod.conf.js 添加上即可解决问题,我只改了webpack.dev.conf.js这一个文件就行了
new webpack.ProvidePlugin({
'window.Quill': 'quill/dist/quill.js',
'Quill': 'quill/dist/quill.js'
})