vue使用quill上传图片的基本配置我在前面文字中详细介绍过(https://segmentfault.com/a/11...)这里主要介绍上传图片,拖拽上传,截图粘贴,调整图片大小的使用。
一、下载安装
cnpm i vue-quill-editor -S
// 可拖拽图片
cnpm i quill-image-drop-module -S
// 这两个是改变图片大小的
cnpm i quill-image-resize-module -S
// 粘贴图片上传
cnpm i quill-image-paste-module -S
二、这些插件需要配置webpack支持,webpack.dev.conf.js/webpack.prod.conf.js
plugins: [
...
new webpack.ProvidePlugin({
'window.Quill': 'quill/dist/quill.js',
'Quill': 'quill/dist/quill.js'
})
...
三、配置组件,最好将富文本编辑器封装成公共组件使用
// 富文本编辑器 quill editor 样式
import 'quill/dist/quill.core.css'
import 'quill/dist/quill.snow.css'
import 'quill/dist/quill.bubble.css'
import * as Quill from 'quill'
import { quillEditor } from 'vue-quill-editor'
// 拖拽上传
import { ImageDrop } from 'quill-image-drop-module'
// 调整上传图片大小
import ImageResize from 'quill-image-resize-module'
// 粘贴图片上传
import {ImageExtend} from 'quill-image-paste-module'
// 注册事件~~~~
Quill.register('modules/imageDrop', ImageDrop)
Quill.register('modules/imageResize', ImageResize)
Quill.register('modules/ImageExtend', ImageExtend)
// html文件
<template>
<div id='quillEditorQiniu'>
<el-row v-loading="loadingImg">
<quill-editor
:style="{width: width ? width: '100%', background: '#fff'}"
v-model="content"
ref="myQuillEditor"
:options="editorOption"
@change="onEditorChange($event)"
>
</quill-editor>
</el-row>
<Upload
class="avatar-uploader"
:accept="'image/*'"
:action="'https://upload.qiniup.com'"
name='file'
:data="updateParams"
:show-upload-list="false"
:on-success="uploadSuccess"
:on-error="uploadError"
:before-upload="beforeUpload"
>
</Upload>
</div>
</template>
// 配置参数
editorOption: {
placeholder: this.placeholder ? this.placeholder : '请输入',
theme: 'snow',
modules: {
toolbar: {
container: toolbarOptions
},
// 拖拽上传
imageDrop: true,
// 调整图片大小
imageResize: {
displayStyles: {
backgroundColor: 'black',
border: 'none',
color: 'white'
},
modules: [ 'Resize', 'DisplaySize', 'Toolbar' ]
},
// 截屏上传
ImageExtend: {
loading: true,
name: 'file',
// 设置上传参数,因为我们要上传七牛,所以需要token
change: (xhr, FormData) => {
FormData.append('token', this.$store.state.upload_token)
},
action: 'https://upload.qiniup.com',
response: (res) => {
console.log(res, 'response')
// 这里有必要说一下,由于七牛上传成功以后返回的是 {hash: 'xxxx', key: 'xxx'},其中key就是七牛生成的文件名称,所以我们拼接上自己的服务器地址,就是图片保存的地址,return
的结果会座位图片的src
return this.$store.getters.upload_url + res.key
}
}
}
},
插件的具体配置可以查看:https://github.com/binperson/...
四、配置参数说明
modules: {
ImageExtend: { // 如果不作设置,即{} 则依然开启复制粘贴功能且以base64插入
name: 'img', // 图片参数名
size: 3, // 可选参数 图片大小,单位为M,1M = 1024kb
action: updateUrl, // 服务器地址, 如果action为空,则采用base64插入图片
// response 为一个函数用来获取服务器返回的具体图片地址
// 例如服务器返回{code: 200; data:{ url: 'baidu.com'}}
// 则 return res.data.url
response: (res) => {
return res.info
},
headers: (xhr) => {
// xhr.setRequestHeader('myHeader','myValue')
}, // 可选参数 设置请求头部
sizeError: () => {}, // 图片超过大小的回调
start: () => {}, // 可选参数 自定义开始上传触发事件
end: () => {}, // 可选参数 自定义上传结束触发的事件,无论成功或者失败
error: () => {}, // 可选参数 上传失败触发的事件
success: () => {}, // 可选参数 上传成功触发的事件
change: (xhr, formData) => {
// xhr.setRequestHeader('myHeader','myValue')
// formData.append('token', 'myToken')
} // 可选参数 每次选择图片触发,也可用来设置头部,但比headers多了一个参数,可设置formData
},
toolbar: { // 如果不上传图片到服务器,此处不必配置
container: container, // container为工具栏,此次引入了全部工具栏,也可自行配置
handlers: {
'image': function () { // 劫持原来的图片点击按钮事件
QuillWatch.emit(this.quill.id)
}
}
}
五、组件代码
<template>
<div id='quillEditorQiniu'>
<el-row v-loading="loadingImg">
<quill-editor
:style="{width: width ? width: '100%', background: '#fff'}"
v-model="content"
ref="myQuillEditor"
:options="editorOption"
@change="onEditorChange($event)"
>
</quill-editor>
</el-row>
<Upload
class="avatar-uploader"
:accept="'image/*'"
:action="'https://upload.qiniup.com'"
name='file'
:data="updateParams"
:show-upload-list="false"
:on-success="uploadSuccess"
:on-error="uploadError"
:before-upload="beforeUpload"
>
</Upload>
</div>
</template>
<script>
import * as Quill from 'quill'
import { quillEditor } from 'vue-quill-editor'
import { ImageDrop } from 'quill-image-drop-module'
import ImageResize from 'quill-image-resize-module'
import {ImageExtend} from 'quill-image-paste-module'
let fontSizeStyle = Quill.import('attributors/style/size')
fontSizeStyle.whitelist = ['12px', '14px', '16px', '20px', '24px', '36px']
Quill.register(fontSizeStyle, true)
Quill.register('modules/imageDrop', ImageDrop)
Quill.register('modules/imageResize', ImageResize)
Quill.register('modules/ImageExtend', ImageExtend)
const toolbarOptions = [
['bold', 'italic', 'underline', 'strike'],
[{'color': ['#000000', '#e60000', '#ff9900', '#ffff00', '#008a00', '#0066cc', '#9933ff', '#ffffff', '#facccc', '#ffebcc', '#ffffcc', '#cce8cc', '#cce0f5', '#ebd6ff', '#bbbbbb', '#f06666', '#ffc266', '#ffff66', '#66b966', '#66a3e0', '#c285ff', '#888888', '#a10000', '#b26b00', '#b2b200', '#006100', '#0047b2', '#6b24b2', '#444444', '#5c0000', '#663d00', '#666600', '#003700', '#002966', '#3d1466']}, { 'size': fontSizeStyle.whitelist }],
[{ list: 'ordered' }, { list: 'bullet' }],
[{ indent: '-1' }, { indent: '+1' }],
['link', 'image']
]
// 自定义编辑器的工作条
export default {
name: 'quill-editor-qiniu',
components: {
quillEditor,
ImageResize
},
props: ['initValue', 'width', 'placeholder'],
created () {
// 获取初始化回显内容
this.content = this.initValue
// 获取上传token
this.$store.dispatch('uploadToken')
},
mounted () {
// 工具栏中的图片图标被单击的时候调用这个方法
let imgHandler = (state) => {
if (state) {
document.querySelector('.avatar-uploader input').click()
}
}
// 当工具栏中的图片图标被单击的时候
this.$refs.myQuillEditor.quill.getModule('toolbar').addHandler('image', imgHandler)
},
data () {
return {
content: '',
editorOption: {
placeholder: this.placeholder ? this.placeholder : '请输入',
theme: 'snow',
modules: {
toolbar: {
container: toolbarOptions
},
// 拖拽上传和调整图片大小
imageDrop: true,
imageResize: {
displayStyles: {
backgroundColor: 'black',
border: 'none',
color: 'white'
},
modules: [ 'Resize', 'DisplaySize', 'Toolbar' ]
},
// 截屏上传
ImageExtend: {
loading: true,
name: 'file',
change: (xhr, FormData) => {
FormData.append('token', this.$store.state.upload_token)
},
action: 'https://upload.qiniup.com',
response: (res) => {
console.log(res, 'response')
return this.$store.getters.upload_url + res.key
}
}
}
},
updateParams: {},
loadingImg: false
}
},
watch: {
initValue: function (newVal, oldVal) {
this.content = newVal
}
},
methods: {
onEditorChange (event) {
console.log(event, 'change')
this.$emit('getEditorInfo', event)
},
beforeUpload (request, file) {
// 设置上传参数
this.updateParams.token = this.$store.state.upload_token
this.updateParams.key = request.name
this.loadingImg = true
},
// 上传图片成功
uploadSuccess (res, file) {
// file 返回的文件信息,也可以在这里调用七牛上传。
console.log(res, file, this.$store.getters.upload_url + res.key, 'success')
// 上传完成以后修改图片地址,回显到quill编辑器中
let quill = this.$refs.myQuillEditor.quill
let length = quill.getSelection() ? quill.getSelection().index : 0
// 插入图片 res.info为服务器返回的图片地址
console.log(this.$store.getters.upload_url + file.name)
// quill.insertEmbed(length, 'image', this.$store.getters.upload_url + file.name)
quill.insertEmbed(length, 'image', this.$store.getters.upload_url + res.key)
// 调整光标到最后
quill.setSelection(length + 1)
this.loadingImg = false
},
// 上传图片失败
uploadError (error, file, list) {
console.log(error, file, list, 'error')
this.loadingImg = false
if (file.error === 'file exists') {
this.$message({type: 'error', message: list.name + ' 已存在,请重新选择!'})
} else {
this.$message({type: 'error', message: list.name + ' 上传出错,请重新上传!'})
}
}
}
}
</script>
<style scoped>
</style>
六、清除复制粘贴样式
1.modules中配置 clipboard选项
editorOption: {
...
modules: {
toolbar: {
container: toolbarOptions
},
clipboard: {
// 粘贴过滤
matchers: [[Node.ELEMENT_NODE, this.HandleCustomMatcher]]
}
...
2.实现HandleCustomMatcher方法,过滤复制粘贴数据
HandleCustomMatcher (node, Delta) {
// 文字、图片等,从别处复制而来,清除自带样式,转为纯文本
let ops = []
Delta.ops.forEach(op => {
if (op.insert && typeof op.insert === 'string') {
ops.push({
insert: op.insert
})
}
})
Delta.ops = ops
return Delta
}
3.这样存在一个问题,如果每次打开编辑框,编辑之前编辑过的内容,就会调clipboard里面的配置,从而调用HandleCustomMatcher方法,quill里面显示的就是去掉样式的内容,所以我们需要添加一个变量,如果是第一次打开编辑器我们不能调用配置文件,清空样式,只有内容发生改变了,是进行了复制粘贴操作,我们才调用配置过滤样式。
data () {
...
once: true // 配置
...
内容改变调用方法
onEditorChange (event) {
this.once = false
复制粘贴配置调用方法
HandleCustomMatcher (node, Delta) {
if (this.once === false) {
// 文字、图片等,从别处复制而来,清除自带样式,转为纯文本
let ops = []
Delta.ops.forEach(op => {
console.log(node, op, '富文本编辑器中的内容')
if (op.insert && (typeof op.insert === 'string' || op.insert.image)) {
ops.push({
insert: op.insert
})
}
})
Delta.ops = ops
return Delta
} else {
return Delta
}
}
}
全部代码,封装上传七牛
<!--
* initValue 默认值 不设置为空
* width 宽度 不设置为100%
* placeholder 提示文字 默认为空
* special 是否开启 输入特殊符号触发弹窗 默认不开启
* specialText 特殊符号 @、#、¥默认为@
* replaceInfo 替换的内容
* getEditorInfo() 返回数据给父组件
-->
<template>
<div id='quillEditorQiniu'>
<el-row v-loading="loadingImg">
<quill-editor
:style="{width: width ? width: '100%', background: '#fff'}"
v-model="content"
ref="myQuillEditor"
:options="editorOption"
@change="onEditorChange($event)"
@focus="focusEvent()"
@blur="blurEvent()"
>
</quill-editor>
</el-row>
<div v-if="special && showSelectList" class="otherInfoList" :style="{left: offsetLeft, top: offsetTop}">
<slot name="changeList"></slot>
</div>
<Upload
:class="classNm"
:accept="'image/*'"
:action="'https://upload.qiniup.com'"
name='file'
:data="updateParams"
:show-upload-list="false"
:on-success="uploadSuccess"
:on-error="uploadError"
:before-upload="beforeUpload"
style="display: none;"
>
</Upload>
</div>
</template>
<script>
import * as Quill from 'quill'
import { quillEditor } from 'vue-quill-editor'
import { ImageDrop } from 'quill-image-drop-module'
import ImageResize from 'quill-image-resize-module'
import {ImageExtend} from 'quill-image-paste-module'
let fontSizeStyle = Quill.import('attributors/style/size')
fontSizeStyle.whitelist = ['12px', '14px', '16px', '20px', '24px', '36px']
Quill.register(fontSizeStyle, true)
Quill.register('modules/imageDrop', ImageDrop)
Quill.register('modules/imageResize', ImageResize)
Quill.register('modules/ImageExtend', ImageExtend)
const toolbarOptions = [
['bold', 'italic', 'underline', 'strike'],
[{'color': ['#000000', '#e60000', '#ff9900', '#ffff00', '#008a00', '#0066cc', '#9933ff', '#ffffff', '#facccc', '#ffebcc', '#ffffcc', '#cce8cc', '#cce0f5', '#ebd6ff', '#bbbbbb', '#f06666', '#ffc266', '#ffff66', '#66b966', '#66a3e0', '#c285ff', '#888888', '#a10000', '#b26b00', '#b2b200', '#006100', '#0047b2', '#6b24b2', '#444444', '#5c0000', '#663d00', '#666600', '#003700', '#002966', '#3d1466']}, { 'size': fontSizeStyle.whitelist }],
[{ list: 'ordered' }, { list: 'bullet' }],
[{ indent: '-1' }, { indent: '+1' }],
['link', 'image']
]
// 自定义编辑器的工作条
export default {
name: 'quill-editor-qiniu',
components: {
quillEditor,
ImageResize
},
props: ['initValue', 'width', 'placeholder', 'special', 'replaceInfo'],
created () {
// 获取初始化回显内容
this.content = this.initValue
// 获取上传token
this.$store.dispatch('uploadToken')
},
mounted () {
this.classNm = 'avatar-uploader' + new Date().getTime()
// 工具栏中的图片图标被单击的时候调用这个方法
let imgHandler = (state) => {
if (state) {
document.querySelector(`.${this.classNm} input`).click()
}
}
// 当工具栏中的图片图标被单击的时候
this.$refs.myQuillEditor.quill.getModule('toolbar').addHandler('image', imgHandler)
},
data () {
return {
classNm: '',
content: '',
once: true,
showSelectList: false,
// 编辑器配置选项
editorOption: {
placeholder: this.placeholder ? this.placeholder : '请输入',
theme: 'snow',
modules: {
toolbar: {
container: toolbarOptions
},
clipboard: {
// 粘贴过滤
matchers: [[Node.ELEMENT_NODE, this.HandleCustomMatcher]]
},
// 拖拽上传和调整图片大小
imageDrop: true,
imageResize: {
displayStyles: {
backgroundColor: 'black',
border: 'none',
color: 'white'
},
modules: [ 'Resize', 'DisplaySize', 'Toolbar' ]
},
// 截屏上传
ImageExtend: {
loading: true,
name: 'file',
change: (xhr, FormData) => {
FormData.append('token', this.$store.state.upload_token)
},
action: 'https://upload.qiniup.com',
response: (res) => {
console.log(res, 'response')
return this.$store.getters.upload_url + res.key
}
}
}
},
updateParams: {},
loadingImg: false,
offsetLeft: 0,
offsetTop: 0
}
},
watch: {
initValue (newVal, oldVal) {
this.content = newVal
},
replaceInfo (newVal, oldVal) {
if (this.special) {
this.content = this._.replace(this.content, '@', newVal)
}
}
},
methods: {
onEditorChange (event) {
this.once = false
console.log(event, 'change', this.content)
// 如果为true标识开启@功能
if (this.special) {
// 计算输入特殊字符显示浮动框的位置
// 获取光标index
let pindex = event.quill.selection.savedRange.index
console.log(pindex)
let arr = event.text.split('\n')
let str = ''
let haveMark = false
for (let index = 0; index < arr.length; index++) {
let value = ' ' + arr[index]
str += value
if (pindex <= str.length) {
console.log(pindex, '循环index的值')
this.offsetTop = (index + 1) * 20 + 'px'
this.offsetLeft = arr[index].lastIndexOf('@') * 14 + 'px'
let newArr = arr[index].split('@')
if (arr[index].lastIndexOf('@') !== -1 && newArr[newArr.length - 1] === '') {
haveMark = true
}
break
} else {
this.offsetTop = 0
this.offsetLeft = 0
}
}
console.log(str.length, '长度', pindex)
console.log(this.offsetTop, this.offsetLeft)
if (pindex && haveMark) {
this.showSelectList = true
} else {
this.showSelectList = false
}
}
this.$emit('getEditorInfo', event)
},
// 选择@的信息
selectItemInfo () {
this.content = 'gaibaile'
},
beforeUpload (request, file) {
// 设置上传参数
this.updateParams.token = this.$store.state.upload_token
this.updateParams.key = request.name
this.loadingImg = true
},
// 上传图片成功
uploadSuccess (res, file) {
// file 返回的文件信息,也可以在这里调用七牛上传。
console.log(res, file, this.$store.getters.upload_url + res.key, 'success')
// 上传完成以后修改图片地址,回显到quill编辑器中
let quill = this.$refs.myQuillEditor.quill
let length = quill.getSelection() ? quill.getSelection().index : 0
// 插入图片 res.info为服务器返回的图片地址
console.log(this.$store.getters.upload_url + file.name)
// quill.insertEmbed(length, 'image', this.$store.getters.upload_url + file.name)
quill.insertEmbed(length, 'image', this.$store.getters.upload_url + res.key)
// 调整光标到最后
quill.setSelection(length + 1)
this.loadingImg = false
},
// 上传图片失败
uploadError (error, file, list) {
console.log(error, file, list, 'error')
this.loadingImg = false
if (file.error === 'file exists') {
this.$message({type: 'error', message: list.name + ' 已存在,请重新选择!'})
} else {
this.$message({type: 'error', message: list.name + ' 上传出错,请重新上传!'})
}
},
focusEvent () {
this.$emit('on-focus')
},
blurEvent () {
this.$emit('on-blur')
},
HandleCustomMatcher (node, Delta) {
if (this.once === false) {
// 文字、图片等,从别处复制而来,清除自带样式,转为纯文本
let ops = []
Delta.ops.forEach(op => {
console.log(node, op, '富文本编辑器中的内容')
if (op.insert && (typeof op.insert === 'string' || op.insert.image)) {
ops.push({
insert: op.insert
})
}
})
Delta.ops = ops
return Delta
} else {
return Delta
}
}
}
}
</script>
<style lang="scss" scoped>
#quillEditorQiniu {
position: relative;
.otherInfoList {
position: absolute;
top: 0px;
left: 0px;
background: #fff;
border: 1px solid #eee;
padding: 10px;
border-radius: 5px;
}
}
</style>