安装方法:npm install -d vue-quill-editor quill vue-cropper
官网:
vue-quill-editor:https://quilljs.com/
git:https://github.com/surmon-china/vue-quill-editor
vue-cropper:https://github.com/xyxiao001/vue-cropper
nuxt框架基于vue的服务端渲染,有报错 Document / Window not defined 的问题,使用富文本编辑器进行组件单独引入的时候会报错,在组件中使用
if (process.client) {
require('external_library')
}
之后element会显示不出来,所以在使用这种引入插件的时候建议直接在
plugins文件夹内直接全局注册,使用服务器渲染
plugins: [
'@/plugins/element-ui',
'@/plugins/bootstrap-vue',
{ src: '@/plugins/map', ssr: false },
{ src: '@/plugins/vue-quill-editor', ssr: false },
{ src: '@/plugins/vue-cropper', ssr: false }
],
组件使用代码:(网上摘取)
在使用上传的时候action是传输一个链接地址,如果想根据自己定义的axios上传需要添加一个auto-upload=”false”意思不取消自动上传更据:on-change=”onChange”(文件状态改变时的钩子,添加文件、上传成功和上传失败时都会被调用)动作进行上传
<template>
<div>
<!-- 图片上传组件-->
<el-upload
:before-upload="beforeUpload"
:show-file-list="false"
accept="image/*"
action=""
class="avatar-uploader"
hidden
name="file"
type='file'>
<el-button size="small" type="primary">点击上传图片 到 文本编辑器</el-button>
</el-upload>
<!-- 编辑器组件-->
<quill-editor
:options="editorOption"
@change="onEditorChange($event)"
class="editor"
ref="myQuillEditor"
v-model="content">
</quill-editor>
<!-- 图片裁剪组件-->
<el-dialog :visible.sync="isShowCropper" top="5vh">
<VueCropper
:autoCrop="option.autoCrop"
:autoCropHeight="option.autoCropHeight"
:autoCropWidth="option.autoCropWidth"
:canScale="option.canScale"
:fixed="option.fixed"
:fixedNumber="option.fixedNumber"
:img="option.img"
:info="option.info"
:outputSize="option.outputSize"
:outputType="option.outputType"
ref="cropper"
style="height:600px;margin:20px 0"
>
</VueCropper>
<br/>
<el-button @click="onCubeImg()" type="primary">生成图片</el-button>
<el-button @click="isShowCropper = false">取消</el-button>
</el-dialog>
</div>
</template>
<script>
// 富文本工具栏配置
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'] // 链接、图片、视频
]
import 'quill/dist/quill.core.css'
import 'quill/dist/quill.snow.css'
import 'quill/dist/quill.bubble.css'
import { uImage } from '@/api/uploadImage.js'
export default {
name: 'textEditor',
components: {},
props: {
/*编辑器的内容*/
value: {
type: String
},
/*图片大小*/
maxSize: {
type: Number,
default: 4000 //kb
}
},
data() {
return {
// 富文本数据
content: '',
quillUpdateImg: false, // 根据图片上传状态来确定是否显示loading动画,刚开始是false,不显示
editorOption: {
theme: 'snow', // or 'bubble'
placeholder: '请输入您想输入的内容',
modules: {
toolbar: {
container: toolbarOptions,
// 和上传按钮进行绑定
handlers: {
image: function(value) {
console.log(value)
if (value) {
// 触发input框选择图片文件
document.querySelector('.avatar-uploader input').click()
} else {
this.quill.format('image', false)
}
}
}
}
}
},
// 切图器数据
option: {
img: '', // 裁剪图片的地址
info: true, // 裁剪框的大小信息
outputSize: 1, // 裁剪生成图片的质量
outputType: 'png', // 裁剪生成图片的格式
canScale: true, // 图片是否允许滚轮缩放
autoCrop: true, // 是否默认生成截图框
autoCropWidth: 150, // 默认生成截图框宽度
autoCropHeight: 150, // 默认生成截图框高度
fixed: true, // 是否开启截图框宽高固定比例
fixedNumber: [4, 4] // 截图框的宽高比例
},
isShowCropper: false,
isClient: true,
width: '150px',
height: '150px'
}
},
methods: {
// 上传切图前调用
beforeUpload(file) {
/**
* URL.createObjectURL(file)生成本地的url
* 返回false终止了自动上传
* */
this.option.img = URL.createObjectURL(file)
this.option.autoCropWidth = this.width
this.option.autoCropHeight = this.height
this.isShowCropper = true
return false
},
// 确定裁剪图片
onCubeImg() {
// 获取cropper的截图的base64 数据data
this.$refs.cropper.getCropData(data => {
//截取bas64 截取base64的格式 和 图片的后缀名
let baseSplit= data.split(',')
let format = baseSplit[0].split('/')[1].split(';')[0]
//获取base64格式的信息
let base = ''
if (process.client) {
base = window.atob(baseSplit[1])
}
//转格式:base64转图片
/**
*格式为:File
* lastModified: 1593134876792
* lastModifiedDate: Fri Jun 26 2020 09:27:56 GMT+0800 (中国标准时间) {}
* name: "img.png"
* size: 15407
* type: "image/png"
* webkitRelativePath: ""
* */
let index = base.length
let u8arr = new Uint8Array(index)
while (index--) {
u8arr[index] = base.charCodeAt(index)
}
let blods = new File([u8arr],'img.' + format,{type: 'image/' + format })
/**
* 建立一个formData表单,之后把上面的base64转换后的格式使用append传递给FormData
* */
let fromData = new FormData()
fromData.append('file',blods)
this.$notify({
title: '成功',
message: '正在上传中',
type: 'success'
});
//发出网络请求
uImage(fromData).then(res => {
this.$notify({
title: '成功',
message: '图片上传成功',
type: 'success'
});
// 获取富文本组件实例
let quill = this.$refs.myQuillEditor.quill
if(res.code === 200){
// 获取光标所在位置
/**
* quill.insertEmbed(length, 'image', res.data.url)
* 图片显示的位置,根据length后的位置显示
* */
if (quill.getSelection() && quill.getSelection().index) {
let length = quill.getSelection().index
quill.insertEmbed(length, 'image', res.data.url)
} else {
let length = 0
quill.insertEmbed(length, 'image', res.data.url)
}
// 调整光标到最后
quill.setSelection(length + 1)
}else {
console.log(res.data.code)
this.$notify({
title: '警告',
message: '图片上传失败',
type: 'warning'
});
}
this.isShowCropper = false
// 先将显示图片地址清空,防止重复显示
this.option.img = ''
})
})
},
onEditorChange() {
console.log(this.content)
//富文本内容改变事件 发送给父级元素
this.$emit('change', this.content)
}
},
mounted() {
setTimeout(() => {
this.content = this.value
}, 500)
}
}
</script>
<style lang="scss">
</style>