在vue里面使用quill的扩展模块vue-quill-editor
效果图:
实现:
1.鼠标悬停时的提示,
2.因为编辑器默认图片是base64格式,所以需要自定义上传图片到服务器,通过服务器给的ID返回给后端,后端再给出URL然后前端插入在编辑器中
3.图片的拖拽和缩放
1、下载Vue-Quill-Editor
npm install vue-quill-editor --save
2、下载quill(Vue-Quill-Editor需要依赖)
npm install quill --save
3、拖拽,缩放模块
npm install quill-image-resize-module quill-image-drop-module --save
两种引用方法:全局引用和局部引用
- 全局引用
项目入口文件中(main.js)注册(也可以写在一个js里面然后把这个js引到main里面)
import Vue from 'vue'
import VueQuillEditor from 'vue-quill-editor'
// require styles
import 'quill/dist/quill.core.css'
import 'quill/dist/quill.snow.css'
import 'quill/dist/quill.bubble.css'
Vue.use(VueQuillEditor)
局部引用,在需调用的vue页面中声明
import 'quill/dist/quill.core.css'
import 'quill/dist/quill.snow.css'
import 'quill/dist/quill.bubble.css'
import {
quillEditor } from 'vue-quill-editor'
export default {
components: {
quillEditor
}
}
局部代码:
<template>
<div>
<quill-editor
ref="myQuillEditor"
@change='onEditorChange'
:content="content"
:options="editorOption"></quill-editor>
</div>
</template>
<script>
import 'quill/dist/quill.core.css'
import 'quill/dist/quill.snow.css'
import 'quill/dist/quill.bubble.css'
import {
quillEditor } from 'vue-quill-editor';
export default {
data(){
return{
content: '',
editorOption: {
placeholder: '编辑文章内容'
},
}
},
components: {
quillEditor
},
methods:{
onEditorChange({
editor, html, text }) {
this.content = html;
},
}
}
</script>
我是全局引入的
全部代码:
<template>
<div class="box">
<el-upload
class="avatar-uploader"
action="#"
name="img"
:show-file-list="false"
:auto-upload="false"
:on-change="changeFile"
:before-upload="beforeUpload">
</el-upload>
<!-- 富文本编辑器组件 -->
<el-row v-loading="uillUpdateImg">
<quill-editor
ref="myQuillEditor"
@change='onEditorChange'
:content="content"
:options="editorOption"></quill-editor>
<!-- 显示字数 -->
<span class="sizeTishi">{
{
tiLength}}/10000</span>
</el-row>
</div>
</template>
<script>
import editorTarbar from '@/utils/editorTarbar' //头部的功能配置
import uploadPicToIOBS from '@/api/content/article/api.js'
import {
saveImageUploadRecord, getIobsUrl } from '@/api/content/article'
export default {
props:{
//我的内容
ArticleContent:{
type: String,
default: ''
}
},
data () {
return {
uillUpdateImg:false, //显示loading动画
content:this.ArticleContent,
tiLength: 0,//默认显示字数
toolbarTips: editorTarbar.toolbarTips,//头部功能的鼠标悬停提示
editorOption:{
modules:{
//图片的缩放和拖拽
imageResize: {
displayStyles: {
backgroundColor: 'black',
border: 'none',
color: 'white'
},
modules: ['Resize', 'DisplaySize', 'Toolbar']
},
toolbar:{
// 工具栏
container: editorTarbar.toolbar,
handlers: {
'image': function (value) {
if (value) {
// upload点击上传事件 value打出来是true,avatar-uploader 就是上面编辑器绑定的class
document.querySelector('.avatar-uploader input').click()
} else {
this.quill.format('image', false)
}
}
}
}
}
},
imageFileList:[],
fileList:[],// 选中的标签
}
},
//一定要有这个,前面么有写这个导致我的字数和内容一直不出来
computed: {
editor() {
return this.$refs.myQuillEditor.quill
}
},
mounted () {
console.log('this is current quill instance object', this.editor)
autotip:{
document.getElementsByClassName('ql-editor')[0].dataset.placeholder=''
for(let item of this.toolbarTips){
let tip = document.querySelector('.quill-editor '+ item.Choice)
if (!tip) continue
tip.setAttribute('title',item.title)}
}
console.log(1111, this.content, this.$refs.myQuillEditor)
this.tiLength = this.$refs.myQuillEditor.quill.getLength()-1
},
//实现双向绑定
watch: {
ArticleContent: function (newVal) {
console.log(123123, newVal);
this.tiLength = this.$refs.myQuillEditor.quill.getLength()-1
this.content = newVal
}
},
methods:{
//内容改变事件
onEditorChange (e){
if(e){
console.log('我被触发改变了',e);
this.content = e.html
this.$emit('change',e.html)
e.quill.deleteText(10000,4)
this.tiLength=this.content===''? 0 : this.tiLength=e.quill.getLength()-1
}
},
// onEditorBlur(){//失去焦点事件
// },
// onEditorFocus(){//获得焦点事件
// },
beforeUpload(){
},
// blob转base64
blobToDataURL(input) {
// 我是上传到专门放图片的服务器,自定义上传图片,原本图片默认是base64 格式的,但是使用el-upload组件上传就不需要转,这里的转格式代码被我删掉了
// 上传图片
uploadPicToIOBS(input).then(res => {
console.log(res, '图片')
// 成功之后拿到返回值,返给后端拿到url
let data={
imageFileId:res[0].imageFileId,
bucket:res[0].bucket,
}
console.log(data);
//发送拿URL的借口请求
getIobsUrl(data).then(res=>{
console.log(res,'我是链接');
if(res.code=='000000'){
//拿到url插入到编辑器中
let quill = this.$refs.myQuillEditor.quill;
//找光标所在位置
let length = quill.getSelection().index
// 插入图片 dt.url为服务器返回的图片地址
quill.insertEmbed(length, 'image', res.data.imageUrl)
// 调整光标到最后
quill.setSelection(length + 1)
}
})
}).catch(err => {
console.log(err, 'errsdscs')
})
},
// 这里注意:自定义上传不会出发成功的回调,所以调用接口写在这里
//上传发生变化时
changeFile(file, fileList) {
console.log(file, fileList, 'changeFile')
this.fileList = fileList.map(item => item)
console.log(this.fileList, 'filterList')
// 如果不修改图片就直接拿之前的图片参数,如果修改就是拿得到的参数
// 转base64
this.blobToDataURL(file.raw)
console.log(this.fileList, '00000')
}
}
}
</script>
<style scoped>
/deep/ .ql-snow .ql-picker {
height: 30px;
}
/deep/ .ql-snow .ql-picker.ql-size {
width: 80px;
}
/deep/ .ql-snow .ql-picker.ql-header {
width: 80px;
}
/deep/ .ql-snow .ql-picker.ql-font {
width: 100px;
}
/* .avatar-uploader{
display: none;
} */
</style>
editorTarbar文件
let toolbar=
[
['bold', 'italic', 'underline', 'strike'], // 加粗,斜体,下划线,删除线buttons
['blockquote', 'code-block'], //引用,代码块
[{
'header': 1 }, {
'header': 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'],//链接,图片
]
let toolbarTips=[
{
Choice:'.ql-bold',title:'加粗'},
{
Choice:'.ql-italic',title:'倾斜'},
{
Choice:'.ql-underline',title:'下划线'},
{
Choice:'.ql-header',title:'段落格式'},
{
Choice:'.ql-strike',title:'删除线'},
{
Choice:'.ql-blockquote',title:'块引用'},
{
Choice:'.ql-code-block',title:'插入代码段'},
{
Choice:'.ql-size',title:'字体大小'},
{
Choice:'.ql-list[value="ordered"]',title:'编号列表'},
{
Choice:'.ql-list[value="bullet"]',title:'项目列表'},
{
Choice:'.ql-header[value="1"]',title:'h1'},
{
Choice:'.ql-header[value="2"]',title:'h2'},
{
Choice:'.ql-align',title:'对齐方式'},
{
Choice:'.ql-color',title:'字体颜色'},
{
Choice:'.ql-background',title:'背景颜色'},
{
Choice:'.ql-image',title:'图像'},
{
Choice:'.ql-video',title:'视频'},
{
Choice:'.ql-link',title:'添加链接'},
{
Choice:'.ql-formula',title:'插入公式'},
{
Choice:'.ql-clean',title:'清除格式'},
{
Choice:'.ql-indent[value="-1"]',title:'向左缩进'},
{
Choice:'.ql-indent[value="+1"]',title:'向右缩进'},
{
Choice:'.ql-direction',title:'文本方向'},
{
Choice:'.ql-header .ql-picker-label',title:'标题大小'},
{
Choice:'.ql-header .ql-picker-item[data-value="1"]',title:'标题一'},
{
Choice:'.ql-header .ql-picker-item[data-value="2"]',title:'标题二'},
{
Choice:'.ql-header .ql-picker-item[data-value="3"]',title:'标题三'},
{
Choice:'.ql-header .ql-picker-item[data-value="4"]',title:'标题四'},
{
Choice:'.ql-header .ql-picker-item[data-value="5"]',title:'标题五'},
{
Choice:'.ql-header .ql-picker-item[data-value="6"]',title:'标题六'},
{
Choice:'.ql-header .ql-picker-item:last-child',title:'标准'},
{
Choice:'.ql-size .ql-picker-item[data-value="small"]',title:'小号'},
{
Choice:'.ql-size .ql-picker-item[data-value="large"]',title:'大号'},
{
Choice:'.ql-size .ql-picker-item[data-value="huge"]',title:'超大号'},
{
Choice:'.ql-size .ql-picker-item:nth-child(2)',title:'标准'},
{
Choice:'.ql-align .ql-picker-item:first-child',title:'居左对齐'},
{
Choice:'.ql-align .ql-picker-item[data-value="center"]',title:'居中对齐'},
{
Choice:'.ql-align .ql-picker-item[data-value="right"]',title:'居右对齐'},
{
Choice:'.ql-align .ql-picker-item[data-value="justify"]',title:'两端对齐'}]
export default {
toolbar,toolbarTips
}
出现的问题:
1:
:auto-upload="false"
这个没写导致我在点击上传图片按钮的时候传了2次。
2:
现实字数,通过后端返回的数据渲染在编辑中,字数不会检测出字数多少,依旧为0
写了watch和computed就解决了
3.拿到url后引入到鼠标光标所在位置